2973 lines
71 KiB
C
2973 lines
71 KiB
C
#include "property.h"
|
||
#include <string.h>
|
||
#include <math.h>
|
||
#include <errno.h>
|
||
#include <limits.h>
|
||
#include "errcode_inc.h"
|
||
|
||
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
|
||
|
||
// #include "ff.h"
|
||
|
||
#if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0))
|
||
#include "sha2.h"
|
||
#endif
|
||
#endif
|
||
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
|
||
#include "mod_bus.h"
|
||
#endif
|
||
|
||
#if (((!defined PROPERTY_PROV_FS_EN) || (PROPERTY_PROV_FS_EN == 0)) && ((!defined PROPERTY_PROV_REMOTE_EN) || (PROPERTY_PROV_REMOTE_EN == 0)))
|
||
#error "define PROPERTY_PROV_FS_EN or PROPERTY_PROV_REMOTE_EN in config.h"
|
||
#endif
|
||
|
||
/**
|
||
* 引入pthread库,确保线程安全
|
||
*/
|
||
#ifdef __linux__
|
||
#include <pthread.h>
|
||
#include <stdlib.h>
|
||
static pthread_mutex_t prop_mutex;
|
||
void prop_lock()
|
||
{
|
||
pthread_mutex_lock(&prop_mutex);
|
||
}
|
||
void prop_unlock()
|
||
{
|
||
pthread_mutex_unlock(&prop_mutex);
|
||
}
|
||
void prop_lock_init()
|
||
{
|
||
pthread_mutex_init(&prop_mutex, NULL);
|
||
}
|
||
void prop_wait(INT32U time)
|
||
{
|
||
}
|
||
#else
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
void prop_lock()
|
||
{
|
||
;
|
||
}
|
||
void prop_unlock()
|
||
{
|
||
;
|
||
}
|
||
void prop_lock_init()
|
||
{
|
||
;
|
||
}
|
||
void prop_wait(INT32U time)
|
||
{
|
||
;
|
||
}
|
||
#endif
|
||
#define config_path "./conf"
|
||
|
||
#define COPY_BUF_SIZE 1024
|
||
#define FLOAT_STRING_LEN 32
|
||
#define UPDATE_LOG "0:/conf/update.%d.log"
|
||
|
||
typedef struct
|
||
{
|
||
const char *key;
|
||
const char *value;
|
||
INT8U success : 1;
|
||
} property_string_item;
|
||
|
||
typedef INT32U (*property_get)(const char *store, const char *id, const char *key, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj);
|
||
typedef INT32U (*property_set)(const char *store, const char *id, property_string_item *list, INT32U count, void *obj);
|
||
typedef INT32U (*property_clear_cache)(const char *store, const char *id, void *obj);
|
||
|
||
typedef struct _sbt_node
|
||
{
|
||
struct _sbt_node *ch[2];
|
||
INT8U valid : 1;
|
||
INT8U tryLocal : 1;
|
||
INT8U isLocal : 1;
|
||
char *key;
|
||
char *value;
|
||
INT32U size;
|
||
} sbt_node;
|
||
|
||
static sbt_node sbt_nil = {{&sbt_nil, &sbt_nil}, 0, 0, 0, NULL, NULL, 0};
|
||
|
||
typedef struct _prop_cache
|
||
{
|
||
char *store;
|
||
char *id;
|
||
sbt_node *sbt;
|
||
struct _prop_cache *next;
|
||
} prop_cache;
|
||
|
||
typedef struct
|
||
{
|
||
struct
|
||
{
|
||
INT32U init : 1;
|
||
INT32U initPending : 1;
|
||
INT32U cache : 1;
|
||
INT32U lock : 1;
|
||
} flag;
|
||
char *id;
|
||
#if (defined RTOS_UCOS)
|
||
OS_EVENT *sem;
|
||
#endif
|
||
property_get get;
|
||
property_set set;
|
||
property_clear_cache clear;
|
||
prop_cache *cache;
|
||
void *obj;
|
||
} property_provider;
|
||
|
||
static property_provider pp[PROPERTY_PROVIDER_MAX];
|
||
static INT8U file_test_random = 0;
|
||
|
||
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
|
||
static INT32U FilePropertyInit(INT32U providerId, const PropertyInitParam *param);
|
||
#endif
|
||
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
|
||
static INT32U RemotePropertyInit(INT32U providerId, const PropertyInitParam *param);
|
||
#endif
|
||
|
||
// linux下malloc是线程安全的
|
||
static void *malloc_mt(size_t size)
|
||
{
|
||
return malloc(size);
|
||
}
|
||
// linux下malloc是线程安全的
|
||
static void free_mt(void *ptr)
|
||
{
|
||
free(ptr);
|
||
}
|
||
|
||
/**
|
||
* SBT(Spine Binary Tree)是一种特殊的二叉树结构,它主要用于处理字符串模式匹配问题。
|
||
SBT的特点是将所有模式字符串的字符按照字典序排列,并将它们连接成一个字符串作为树的主干(Spine),每个模式字符串作为树的一个分支。在SBT中,模式字符串的公共前缀被共享,从而减少了树的高度,提高了匹配效率。
|
||
*/
|
||
static void SBT_Rotate(sbt_node **x, BOOL flag)
|
||
{
|
||
// 旋转:flag == 0为左旋,否则为右旋
|
||
sbt_node *y = (*x)->ch[!flag];
|
||
(*x)->ch[!flag] = y->ch[flag];
|
||
y->ch[flag] = *x;
|
||
y->size = (*x)->size;
|
||
(*x)->size = (*x)->ch[0]->size + (*x)->ch[1]->size + 1;
|
||
*x = y;
|
||
}
|
||
|
||
static void SBT_Maintain(sbt_node **t, BOOL flag)
|
||
{
|
||
// 维护操作的核心:保持
|
||
if ((*t)->ch[flag]->ch[flag]->size > (*t)->ch[!flag]->size)
|
||
{ // 情况1
|
||
SBT_Rotate(t, !flag);
|
||
}
|
||
else if ((*t)->ch[flag]->ch[!flag]->size > (*t)->ch[!flag]->size)
|
||
{ // 情况2
|
||
SBT_Rotate(&(*t)->ch[flag], flag);
|
||
SBT_Rotate(t, !flag);
|
||
}
|
||
else
|
||
{ // 无需修复
|
||
return;
|
||
}
|
||
SBT_Maintain(&(*t)->ch[0], 0); // 修复左子树
|
||
SBT_Maintain(&(*t)->ch[1], 1); // 修复右子树
|
||
SBT_Maintain(t, 0); // 修复整棵树
|
||
SBT_Maintain(t, 1);
|
||
}
|
||
|
||
static INT32U SBT_Depth(sbt_node *t)
|
||
{
|
||
INT32U d[2];
|
||
if (t == &sbt_nil)
|
||
return 0;
|
||
d[0] = SBT_Depth(t->ch[0]);
|
||
d[1] = SBT_Depth(t->ch[1]);
|
||
if (d[0] > d[1])
|
||
return (d[0] + 1);
|
||
return (d[1] + 1);
|
||
}
|
||
|
||
// static INT32U SBT_Check(sbt_node* t) {
|
||
// if (((INT32U)t < 0xa0000000) || ((INT32U)t >= 0xa0800000))
|
||
// return RET_OS_HEAP_CORRUPTED;
|
||
// if (t == &sbt_nil)
|
||
// return RET_EXT_NO_ERROR;
|
||
// if (!SBT_Check(t->ch[0]))
|
||
// return RET_OS_HEAP_CORRUPTED;
|
||
// if (!SBT_Check(t->ch[1]))
|
||
// return RET_OS_HEAP_CORRUPTED;
|
||
// return RET_EXT_NO_ERROR;
|
||
// }
|
||
|
||
static int SBT_NodeCmp(sbt_node *x, BOOL yl, const char *ykey)
|
||
{
|
||
if ((x->tryLocal != 0) && (yl == 0))
|
||
return 1;
|
||
if ((x->tryLocal == 0) && (yl != 0))
|
||
return -1;
|
||
if (x->key == ykey) // 两者均为NULL返回0
|
||
return 0;
|
||
if (ykey == NULL) // 至少有一个不为NULL, y->key == NULL 则 x->key != NULL
|
||
return 1;
|
||
if (x->key == NULL)
|
||
return -1;
|
||
return strcmp(x->key, ykey);
|
||
}
|
||
|
||
static sbt_node *SBT_Search(sbt_node *t, BOOL local, const char *key)
|
||
{
|
||
// 在T中中寻找关键字为key的结点
|
||
// 若能找到则返回指向它的指针,否则返回NULL
|
||
int cmp;
|
||
if (t == &sbt_nil)
|
||
return NULL;
|
||
cmp = SBT_NodeCmp(t, local, key);
|
||
if (cmp == 0)
|
||
return t;
|
||
return SBT_Search(t->ch[cmp < 0], local, key);
|
||
}
|
||
|
||
static void SBT_Insert(sbt_node **t, sbt_node *x)
|
||
{
|
||
// 将节点x插入树中
|
||
if ((*t) == &sbt_nil)
|
||
{
|
||
(*t) = x;
|
||
}
|
||
else
|
||
{
|
||
int cmp = SBT_NodeCmp(x, (*t)->tryLocal, (*t)->key);
|
||
if (cmp == 0)
|
||
{
|
||
sbt_node *old = *t;
|
||
x->ch[0] = old->ch[0];
|
||
x->ch[1] = old->ch[1];
|
||
*t = x;
|
||
free_mt(old->key);
|
||
if (old->value != NULL)
|
||
free_mt(old->value);
|
||
free_mt(old);
|
||
}
|
||
else
|
||
{
|
||
(*t)->size++;
|
||
SBT_Insert(&(*t)->ch[cmp > 0], x);
|
||
SBT_Maintain(t, (cmp > 0));
|
||
}
|
||
}
|
||
}
|
||
|
||
static void SBT_Delete(sbt_node *t)
|
||
{
|
||
if (t == &sbt_nil)
|
||
return;
|
||
SBT_Delete(t->ch[0]);
|
||
SBT_Delete(t->ch[1]);
|
||
free_mt(t->key);
|
||
if (t->value != NULL)
|
||
free_mt(t->value);
|
||
}
|
||
|
||
/**
|
||
* ram缓存
|
||
*/
|
||
static sbt_node *CacheGet(property_provider *p, const char *store, const char *id, BOOL local, const char *key)
|
||
{
|
||
prop_cache *ptr;
|
||
sbt_node *node;
|
||
if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return NULL;
|
||
for (ptr = p->cache; ptr != NULL; ptr = ptr->next)
|
||
if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0))))
|
||
break;
|
||
if (ptr == NULL)
|
||
return NULL;
|
||
node = SBT_Search(ptr->sbt, local, key);
|
||
if (node == NULL)
|
||
return NULL;
|
||
if (!node->valid)
|
||
return NULL;
|
||
return node;
|
||
}
|
||
|
||
static INT32U CacheSet(property_provider *p, const char *store, const char *id, BOOL tryLocal, const char *key, const char *value, BOOL isLocal)
|
||
{
|
||
prop_cache *ptr;
|
||
sbt_node *node;
|
||
INT32U keyLen, valLen;
|
||
if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
node = (sbt_node *)malloc_mt(sizeof(sbt_node));
|
||
if (node == NULL)
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
keyLen = strlen(key);
|
||
valLen = strlen(value);
|
||
node->ch[0] = &sbt_nil;
|
||
node->ch[1] = &sbt_nil;
|
||
node->valid = TRUE;
|
||
node->tryLocal = tryLocal;
|
||
node->isLocal = isLocal;
|
||
node->size = 1;
|
||
node->key = (char *)malloc_mt(keyLen + 1);
|
||
if (node->key == NULL)
|
||
{
|
||
free_mt(node);
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
else
|
||
{
|
||
strncpy(node->key, key, keyLen);
|
||
node->key[keyLen] = 0;
|
||
}
|
||
if (value == NULL)
|
||
{
|
||
node->value = NULL;
|
||
}
|
||
else
|
||
{
|
||
node->value = (char *)malloc_mt(valLen + 1);
|
||
if (value == NULL)
|
||
{
|
||
free_mt(node->key);
|
||
free_mt(node);
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
else
|
||
{
|
||
strncpy(node->value, value, valLen);
|
||
node->value[valLen] = 0;
|
||
}
|
||
}
|
||
|
||
for (ptr = p->cache; ptr != NULL; ptr = ptr->next)
|
||
if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0))))
|
||
break;
|
||
if (ptr == NULL)
|
||
{
|
||
ptr = (prop_cache *)malloc_mt(sizeof(prop_cache));
|
||
if (ptr != NULL)
|
||
{
|
||
BOOL mallocErr = FALSE;
|
||
ptr->store = NULL;
|
||
ptr->id = NULL;
|
||
if ((id != NULL) && (*id != 0))
|
||
{
|
||
INT32U idLen = strlen(id);
|
||
ptr->id = (char *)malloc_mt(idLen + 1);
|
||
if (ptr->id == NULL)
|
||
{
|
||
mallocErr = TRUE;
|
||
}
|
||
else
|
||
{
|
||
strncpy(ptr->id, id, idLen);
|
||
ptr->id[idLen] = 0;
|
||
}
|
||
}
|
||
if (!mallocErr)
|
||
{
|
||
INT32U storeLen = strlen(store);
|
||
ptr->store = (char *)malloc_mt(storeLen + 1);
|
||
if (ptr->store == NULL)
|
||
{
|
||
mallocErr = TRUE;
|
||
}
|
||
else
|
||
{
|
||
strncpy(ptr->store, store, storeLen);
|
||
ptr->store[storeLen] = 0;
|
||
}
|
||
}
|
||
if (mallocErr)
|
||
{
|
||
if (ptr->store != NULL)
|
||
free_mt(ptr->store);
|
||
if (ptr->id != NULL)
|
||
free_mt(ptr->id);
|
||
free_mt(ptr);
|
||
ptr = NULL;
|
||
}
|
||
else
|
||
{
|
||
ptr->sbt = &sbt_nil;
|
||
ptr->next = p->cache;
|
||
p->cache = ptr;
|
||
}
|
||
}
|
||
}
|
||
if (ptr == NULL)
|
||
{
|
||
free_mt(node->key);
|
||
if (node->value != NULL)
|
||
free_mt(node->value);
|
||
free_mt(node);
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
SBT_Insert(&ptr->sbt, node);
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
static INT32U CacheInvalid(property_provider *p, const char *store, const char *id, BOOL tryLocal, const char *key)
|
||
{
|
||
prop_cache *ptr;
|
||
sbt_node *node;
|
||
|
||
if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
|
||
for (ptr = p->cache; ptr != NULL; ptr = ptr->next)
|
||
if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0))))
|
||
break;
|
||
if (ptr == NULL)
|
||
return RET_EXT_NO_ERROR;
|
||
|
||
node = SBT_Search(ptr->sbt, tryLocal, key);
|
||
if (node != NULL)
|
||
node->valid = FALSE;
|
||
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
// store == NULL时清除全部cache
|
||
// store != NULL && id == NULL时清除store相关的全部cache
|
||
// store != NULL && id != NULL时清除(store, id)的cache
|
||
static INT32U CacheClear(property_provider *p, const char *store, const char *id)
|
||
{
|
||
if (p == NULL)
|
||
return NULL;
|
||
if ((store == NULL) || (*store == 0))
|
||
{
|
||
prop_cache *ptr;
|
||
for (ptr = p->cache; ptr != NULL;)
|
||
{
|
||
prop_cache *tmp = ptr;
|
||
ptr = ptr->next;
|
||
free_mt(tmp->store);
|
||
if (tmp->id != NULL)
|
||
free_mt(tmp->id);
|
||
SBT_Delete(tmp->sbt);
|
||
free_mt(tmp);
|
||
}
|
||
p->cache = NULL;
|
||
}
|
||
else if ((id == NULL) || (*id == 0))
|
||
{
|
||
prop_cache *ptr;
|
||
prop_cache *tail = NULL;
|
||
for (ptr = p->cache; ptr != NULL;)
|
||
{
|
||
if (strcmp(store, ptr->store) == 0)
|
||
{
|
||
prop_cache *tmp = ptr;
|
||
if (ptr == p->cache)
|
||
p->cache = ptr->next;
|
||
else
|
||
tail->next = ptr->next;
|
||
ptr = ptr->next;
|
||
free_mt(tmp->store);
|
||
if (tmp->id != NULL)
|
||
free_mt(tmp->id);
|
||
SBT_Delete(tmp->sbt);
|
||
free_mt(tmp);
|
||
}
|
||
else
|
||
{
|
||
tail = ptr;
|
||
ptr = ptr->next;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
prop_cache *ptr;
|
||
prop_cache *tail = NULL;
|
||
for (ptr = p->cache; ptr != NULL; tail = ptr, ptr = ptr->next)
|
||
if ((strcmp(store, ptr->store) == 0) && ((ptr->id != NULL) && (strcmp(id, ptr->id) == 0)))
|
||
break;
|
||
if (ptr != NULL)
|
||
{
|
||
if (ptr == p->cache)
|
||
p->cache = ptr->next;
|
||
else
|
||
tail->next = ptr->next;
|
||
free_mt(ptr->store);
|
||
if (ptr->id != NULL)
|
||
free_mt(ptr->id);
|
||
SBT_Delete(ptr->sbt);
|
||
free_mt(ptr);
|
||
}
|
||
}
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
static void CheckInit(void)
|
||
{
|
||
static INT8U init = 0;
|
||
prop_lock();
|
||
if (init == 0)
|
||
{
|
||
INT8U i;
|
||
for (i = 0; i < PROPERTY_PROVIDER_MAX; i++)
|
||
{
|
||
pp[i].flag.init = 0;
|
||
pp[i].flag.initPending = 0;
|
||
pp[i].flag.cache = 0;
|
||
pp[i].id = NULL;
|
||
pp[i].get = NULL;
|
||
pp[i].set = NULL;
|
||
pp[i].clear = NULL;
|
||
pp[i].cache = NULL;
|
||
pp[i].obj = NULL;
|
||
}
|
||
init = 1;
|
||
}
|
||
prop_unlock();
|
||
}
|
||
|
||
// key规则检查
|
||
static INT32U CheckKey(const char *key)
|
||
{
|
||
if ((key == NULL) || (*key == '\0'))
|
||
return RET_OS_INVALID_PARAM;
|
||
if (((key[0] >= 'a') && (key[0] <= 'z')) || ((key[0] >= 'A') && (key[0] <= 'Z')))
|
||
{
|
||
INT32U i;
|
||
for (i = 1; key[i] != '\0'; i++)
|
||
{
|
||
if (((key[i] >= 'a') && (key[i] <= 'z')) || ((key[i] >= 'A') && (key[i] <= 'Z')) || ((key[i] >= '0') && (key[i] <= '9')) || (key[i] == '-') || (key[i] == '_') || (key[i] == '.') || (key[i] == '[') || (key[i] == ']'))
|
||
continue;
|
||
return RET_PROPERTY_INVALID_KEY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return RET_PROPERTY_INVALID_KEY;
|
||
}
|
||
// printf("key name is ok\n");
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
// TODO:
|
||
INT32U PropertyInit(INT32U providerId, const PropertyInitParam *param)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
BOOL doInit = FALSE;
|
||
CheckInit();
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (param == NULL) || ((param->id != NULL) && (strlen(param->id) > PROPERTY_ID_MAX)))
|
||
return RET_OS_INVALID_PARAM;
|
||
#if 0 // 这段代码没必要存在 CheckInit()——>pp[providerId].flag.initPending=0
|
||
for (;;)
|
||
{
|
||
BOOL quit = FALSE;
|
||
prop_lock();
|
||
if (pp[providerId].flag.initPending == 0)
|
||
{
|
||
if (pp[providerId].flag.init == 0)
|
||
{
|
||
doInit = TRUE;
|
||
pp[providerId].flag.initPending = 1;
|
||
}
|
||
quit = TRUE;
|
||
}
|
||
prop_unlock();
|
||
if (quit)
|
||
break;
|
||
prop_wait(1000);
|
||
}
|
||
#else // 直接启动初始化
|
||
doInit = TRUE;
|
||
#endif
|
||
if (doInit)
|
||
{
|
||
char *id = NULL;
|
||
if ((ret == RET_EXT_NO_ERROR) && (param->id != NULL) && (*param->id != 0))
|
||
{
|
||
INT32U idLen = strlen(param->id);
|
||
id = (char *)malloc_mt(idLen + 1);
|
||
if (id == NULL)
|
||
{
|
||
ret = RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
else
|
||
{
|
||
strncpy(id, param->id, idLen);
|
||
id[idLen] = 0;
|
||
}
|
||
}
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
pp[providerId].id = id;
|
||
if (param->type == PropertyTypeFS)
|
||
{
|
||
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
|
||
// 锁初始化
|
||
prop_lock_init();
|
||
|
||
ret = FilePropertyInit(providerId, param);
|
||
#else
|
||
ret = RET_OS_NOT_IMPLEMENT;
|
||
#endif
|
||
}
|
||
else if (param->type == PropertyTypeRemote)
|
||
{
|
||
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
|
||
#if (defined RTOS_UCOS)
|
||
pp[providerId].sem = OSSemCreate(1);
|
||
if (pp[providerId].sem == NULL)
|
||
{
|
||
ret = RET_OS_NO_AVAILABLE_EVENT_CTRL_BLK;
|
||
}
|
||
else
|
||
{
|
||
#endif
|
||
ret = RemotePropertyInit(providerId, param);
|
||
#if (defined RTOS_UCOS)
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
{
|
||
INT8U osErr = OS_ERR_NONE;
|
||
OSSemDel(pp[providerId].sem, OS_DEL_ALWAYS, &osErr);
|
||
pp[providerId].sem = NULL;
|
||
}
|
||
}
|
||
#endif
|
||
#else
|
||
ret = RET_OS_NOT_IMPLEMENT;
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
ret = RET_OS_INVALID_PARAM;
|
||
}
|
||
}
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
{
|
||
if (id != NULL)
|
||
free_mt(id);
|
||
pp[providerId].id = NULL;
|
||
}
|
||
pp[providerId].flag.initPending = 0;
|
||
}
|
||
// PROP_ENABLE_IRQ();
|
||
return ret;
|
||
}
|
||
|
||
INT32U GetProperty(INT32U providerId, const char *store, const char *id, const char *key, BOOL tryLocal, char *value, INT32U sizeOfValue, BOOL *isLocal)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
sbt_node *node = NULL;
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (value == NULL) || (sizeOfValue == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
// 检查key命名规范
|
||
ret = CheckKey(key);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
return ret;
|
||
// 检查是否init
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
if (pp[providerId].get == NULL)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
if ((id == NULL) || (*id == 0))
|
||
id = pp[providerId].id;
|
||
if (tryLocal && ((id == NULL) || (*id == 0)))
|
||
return RET_PROPERTY_INVALID_STORE_ID;
|
||
// 加锁
|
||
prop_lock();
|
||
if (pp[providerId].flag.cache)
|
||
node = CacheGet(&pp[providerId], store, id, tryLocal, key);
|
||
if (node == NULL)
|
||
{
|
||
BOOL lt = TRUE;
|
||
ret = pp[providerId].get(store, key, (tryLocal ? id : NULL), value, sizeOfValue, <, pp[providerId].obj);
|
||
|
||
if (pp[providerId].flag.cache)
|
||
{
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
CacheSet(&pp[providerId], store, id, tryLocal, key, value, lt);
|
||
else if (ret == RET_PROPERTY_NOT_FOUND)
|
||
CacheSet(&pp[providerId], store, id, tryLocal, key, NULL, lt);
|
||
}
|
||
if (isLocal != NULL)
|
||
*isLocal = lt;
|
||
}
|
||
else if (node->value == NULL)
|
||
{
|
||
ret = RET_PROPERTY_NOT_FOUND;
|
||
}
|
||
else
|
||
{
|
||
INT32U valLen = strlen(node->value);
|
||
if (valLen > sizeOfValue - 1)
|
||
{
|
||
valLen = sizeOfValue - 1;
|
||
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
|
||
}
|
||
strncpy(value, node->value, valLen);
|
||
value[valLen] = 0;
|
||
if (isLocal != NULL)
|
||
*isLocal = node->isLocal;
|
||
}
|
||
prop_unlock();
|
||
return ret;
|
||
}
|
||
|
||
INT32U SetProperty(INT32U providerId, const char *store, const char *id, const char *key, const char *value)
|
||
{
|
||
PropertyItem item;
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
item.key = key;
|
||
if (value == NULL)
|
||
{
|
||
item.type = VT_NULL;
|
||
item.value.str = NULL;
|
||
}
|
||
else
|
||
{
|
||
item.type = VT_STR;
|
||
item.value.str = value;
|
||
}
|
||
item.success = 0;
|
||
return SetPropertyList(providerId, store, id, &item, 1);
|
||
}
|
||
|
||
INT32U SetPropertyList(INT32U providerId, const char *store, const char *id, PropertyItem *list, INT32U count)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
property_string_item *bufList;
|
||
char *stringList;
|
||
BOOL fpChked = FALSE;
|
||
INT32U idx;
|
||
|
||
if (providerId >= PROPERTY_PROVIDER_MAX)
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
if (pp[providerId].set == NULL)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
if ((id == NULL) || (*id == 0))
|
||
id = pp[providerId].id;
|
||
if ((id == NULL) || (*id == 0))
|
||
return RET_PROPERTY_INVALID_STORE_ID;
|
||
|
||
if (count == 0)
|
||
return RET_EXT_NO_ERROR;
|
||
|
||
bufList = (property_string_item *)malloc_mt(sizeof(property_string_item) * count);
|
||
stringList = ((bufList == NULL) ? NULL : (char *)malloc_mt((FLOAT_STRING_LEN + 1) * count));
|
||
if ((bufList == NULL) || (stringList == NULL))
|
||
{
|
||
if (bufList != NULL)
|
||
free_mt(bufList);
|
||
if (stringList != NULL)
|
||
free_mt(stringList);
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
|
||
memset(stringList, 0, ((FLOAT_STRING_LEN + 1) * count));
|
||
for (idx = 0; idx < count; idx++)
|
||
{
|
||
ret = CheckKey(list[idx].key);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
break;
|
||
bufList[idx].key = list[idx].key;
|
||
switch (list[idx].type)
|
||
{
|
||
case VT_NULL:
|
||
bufList[idx].value = NULL;
|
||
break;
|
||
case VT_I4:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i4);
|
||
break;
|
||
case VT_I2:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i2);
|
||
break;
|
||
case VT_I1:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i1);
|
||
break;
|
||
case VT_UI4:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui4);
|
||
break;
|
||
case VT_UI2:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui2);
|
||
break;
|
||
case VT_UI1:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui1);
|
||
break;
|
||
case VT_R4:
|
||
if (!fpChked)
|
||
{
|
||
char str[10];
|
||
snprintf(str, sizeof(str), "%e", PI);
|
||
if (strncmp(str, "3.14159", strlen("3.14159")) == 0)
|
||
fpChked = TRUE;
|
||
else
|
||
ret = RET_OS_FLOAT_TEST_FAILED;
|
||
}
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%e", ((isfinite(list[idx].value.r4) || isinf(list[idx].value.r4)) ? list[idx].value.r4 : NAN));
|
||
}
|
||
break;
|
||
case VT_STR:
|
||
bufList[idx].value = list[idx].value.str;
|
||
break;
|
||
case VT_BIT4:
|
||
bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx];
|
||
snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", ((GetUnsigned(providerId, store, list[idx].key, TRUE, 0, NULL, NULL) & (~list[idx].value.bit4.mask)) | (list[idx].value.bit4.val & list[idx].value.bit4.mask)));
|
||
break;
|
||
}
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
break;
|
||
bufList[idx].success = 0;
|
||
}
|
||
prop_lock();
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
ret = pp[providerId].set(store, id, bufList, count, pp[providerId].obj);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
for (idx = 0; idx < count; idx++)
|
||
{
|
||
if ((bufList[idx].value == NULL) || (CacheSet(&pp[providerId], store, id, TRUE, bufList[idx].key, bufList[idx].value, TRUE) != RET_EXT_NO_ERROR))
|
||
CacheInvalid(&pp[providerId], store, id, TRUE, bufList[idx].key);
|
||
}
|
||
}
|
||
}
|
||
prop_unlock();
|
||
free_mt(bufList);
|
||
free_mt(stringList);
|
||
return ret;
|
||
}
|
||
|
||
INT32S GetInteger(INT32U providerId, const char *store, const char *key, BOOL tryLocal, INT32S defaultValue, INT32U *retCode, BOOL *isLocal)
|
||
{
|
||
char result[PROPERTY_LINE_MAX + 1];
|
||
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
|
||
INT32S val = 0;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
char *endptr = NULL;
|
||
val = strtol(result, &endptr, 0);
|
||
if (endptr == result)
|
||
{
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
}
|
||
else
|
||
{
|
||
for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++)
|
||
;
|
||
if (*endptr != 0)
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
else if ((errno == ERANGE) && ((val == LONG_MIN) || (val == LONG_MAX)))
|
||
ret = RET_PROPERTY_ERANGE;
|
||
}
|
||
}
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
val = defaultValue;
|
||
if (retCode != NULL)
|
||
*retCode = ret;
|
||
return val;
|
||
}
|
||
|
||
INT32U GetUnsigned(INT32U providerId, const char *store, const char *key, BOOL tryLocal, INT32U defaultValue, INT32U *retCode, BOOL *isLocal)
|
||
{
|
||
char result[PROPERTY_LINE_MAX + 1];
|
||
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
|
||
INT32U val = 0;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
char *endptr = NULL;
|
||
val = strtoul(result, &endptr, 0);
|
||
if (endptr == result)
|
||
{
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
}
|
||
else
|
||
{
|
||
for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++)
|
||
;
|
||
if (*endptr != 0)
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
else if ((errno == ERANGE) && (val == ULONG_MAX))
|
||
ret = RET_PROPERTY_ERANGE;
|
||
}
|
||
}
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
val = defaultValue;
|
||
if (retCode != NULL)
|
||
*retCode = ret;
|
||
return val;
|
||
}
|
||
|
||
FP32 GetFloat(INT32U providerId, const char *store, const char *key, BOOL tryLocal, FP32 defaultValue, INT32U *retCode, BOOL *isLocal)
|
||
{
|
||
char result[PROPERTY_LINE_MAX + 1];
|
||
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
|
||
FP32 val = FP_ZERO;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
char *endptr = NULL;
|
||
val = strtof(result, &endptr);
|
||
if (!isfinite(val) && !isinf(val))
|
||
{
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
}
|
||
else if (endptr == result)
|
||
{
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
}
|
||
else
|
||
{
|
||
for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++)
|
||
;
|
||
if (*endptr != 0)
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
else if ((errno == ERANGE) && isinf(val))
|
||
ret = RET_PROPERTY_ERANGE;
|
||
}
|
||
}
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
val = defaultValue;
|
||
if (retCode != NULL)
|
||
*retCode = ret;
|
||
return val;
|
||
}
|
||
|
||
BOOL GetBoolean(INT32U providerId, const char *store, const char *key, BOOL tryLocal, BOOL defaultValue, INT32U *retCode, BOOL *isLocal)
|
||
{
|
||
INT32U i;
|
||
char result[PROPERTY_LINE_MAX + 1];
|
||
INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal);
|
||
BOOL val = defaultValue;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
for (i = 0; ((i < sizeof(result)) && (result[i] != '\0')); i++)
|
||
if ((result[i] >= 'A') && (result[i] <= 'Z'))
|
||
result[i] += ('a' - 'A');
|
||
if ((strcmp("true", result) == 0) || (strcmp("yes", result) == 0) || (strcmp("1", result) == 0))
|
||
{
|
||
val = TRUE;
|
||
}
|
||
else if ((strcmp("false", result) == 0) || (strcmp("no", result) == 0) || (strcmp("0", result) == 0))
|
||
{
|
||
val = FALSE;
|
||
}
|
||
else
|
||
{
|
||
ret = RET_PROPERTY_EFORMAT;
|
||
}
|
||
}
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
val = defaultValue;
|
||
if (retCode != NULL)
|
||
*retCode = ret;
|
||
return val;
|
||
}
|
||
|
||
INT32U SetInteger(INT32U providerId, const char *store, const char *key, INT32S value)
|
||
{
|
||
PropertyItem item;
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
item.key = key;
|
||
item.type = VT_I4;
|
||
item.value.i4 = value;
|
||
item.success = 0;
|
||
return SetPropertyList(providerId, store, NULL, &item, 1);
|
||
}
|
||
|
||
INT32U SetUnsigned(INT32U providerId, const char *store, const char *key, INT32U value)
|
||
{
|
||
PropertyItem item;
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
item.key = key;
|
||
item.type = VT_UI4;
|
||
item.value.ui4 = value;
|
||
item.success = 0;
|
||
return SetPropertyList(providerId, store, NULL, &item, 1);
|
||
}
|
||
|
||
INT32U SetFloat(INT32U providerId, const char *store, const char *key, FP32 value)
|
||
{
|
||
PropertyItem item;
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
item.key = key;
|
||
item.type = VT_R4;
|
||
item.value.r4 = value;
|
||
item.success = 0;
|
||
return SetPropertyList(providerId, store, NULL, &item, 1);
|
||
}
|
||
|
||
INT32U SetBits(INT32U providerId, const char *store, const char *key, INT32U value, INT32U mask)
|
||
{
|
||
PropertyItem item;
|
||
if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
if (mask == 0)
|
||
return RET_EXT_NO_ERROR;
|
||
item.key = key;
|
||
item.type = VT_BIT4;
|
||
item.value.bit4.val = value;
|
||
item.value.bit4.mask = mask;
|
||
item.success = 0;
|
||
return SetPropertyList(providerId, store, NULL, &item, 1);
|
||
}
|
||
|
||
INT32U ClearPropertyCache(INT32U providerId, const char *store, const char *id)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
if (providerId >= PROPERTY_PROVIDER_MAX)
|
||
return RET_OS_INVALID_PARAM;
|
||
CheckInit();
|
||
if (pp[providerId].flag.init == 0)
|
||
return RET_PROPERTY_NOT_INIT;
|
||
if (pp[providerId].clear == NULL)
|
||
return RET_EXT_NO_ERROR;
|
||
if ((id == NULL) || (*id == 0))
|
||
id = pp[providerId].id;
|
||
if ((id == NULL) || (*id == 0))
|
||
id = NULL;
|
||
|
||
prop_lock();
|
||
|
||
CacheClear(&pp[providerId], store, id);
|
||
ret = pp[providerId].clear(store, id, pp[providerId].obj);
|
||
|
||
prop_unlock();
|
||
return ret;
|
||
}
|
||
|
||
INT32U SetPropertyTestCase(INT32U caseId)
|
||
{
|
||
if (caseId == 1)
|
||
file_test_random = 1; // 随机数设为非0表示启用测试, 也可以设成其他非0值, 该值在测试过程中会被随机更新
|
||
else
|
||
file_test_random = 0; // 随机数设为0表示禁用测试, 不会再被更新
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
// INT32U VerifyPropertyCache(INT32U providerId) {
|
||
// INT32U ret = RET_EXT_NO_ERROR;
|
||
// prop_cache* ptr;
|
||
// #if (defined RTOS_UCOS)
|
||
// INT8U osErr = OS_ERR_NONE;
|
||
// #endif
|
||
//
|
||
// if (providerId >= PROPERTY_PROVIDER_MAX)
|
||
// return RET_OS_INVALID_PARAM;
|
||
// CheckInit();
|
||
// if (pp[providerId].flag.init == 0)
|
||
// return RET_PROPERTY_NOT_INIT;
|
||
//
|
||
// #if (defined RTOS_UCOS)
|
||
// OSSemPend(pp[providerId].sem, OSmsToTick(1000UL), &osErr);
|
||
// if (osErr != OS_ERR_NONE)
|
||
// return RET_OS_SYNC_OBJ_FAILED;
|
||
// #elif ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1))
|
||
// PROP_DISABLE_IRQ();
|
||
// if (pp[providerId].flag.lock != 0)
|
||
// ret = RET_OS_SYNC_OBJ_FAILED;
|
||
// else
|
||
// pp[providerId].flag.lock = 1;
|
||
// PROP_ENABLE_IRQ();
|
||
// if (ret != RET_EXT_NO_ERROR)
|
||
// return ret;
|
||
// #else
|
||
// #error "Target error"
|
||
// #endif
|
||
//
|
||
// for (ptr = pp[providerId].cache; ptr != NULL; ptr = ptr->next) {
|
||
// if (((INT32U)ptr < 0xa0000000) || ((INT32U)ptr >= 0xa0800000)) {
|
||
// ret = RET_OS_HEAP_CORRUPTED;
|
||
// break;
|
||
// }
|
||
// ret = SBT_Check(ptr->sbt);
|
||
// if (ret != RET_EXT_NO_ERROR)
|
||
// break;
|
||
// }
|
||
//
|
||
// PROP_UNLOCK(pp[providerId]);
|
||
//
|
||
// return ret;
|
||
//}
|
||
|
||
#if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0))
|
||
|
||
/**************************************************************
|
||
* File property provider
|
||
*************************************************************
|
||
*/
|
||
|
||
typedef struct _fileprop_cache
|
||
{
|
||
char *key;
|
||
char *value;
|
||
INT32U size;
|
||
struct _fileprop_cache *next;
|
||
} fileprop_cache;
|
||
|
||
typedef struct _file_cache
|
||
{
|
||
BOOL allCache;
|
||
char *store;
|
||
char *id;
|
||
fileprop_cache *cache;
|
||
struct _file_cache *next;
|
||
} file_cache;
|
||
|
||
typedef struct
|
||
{
|
||
#if (!defined RTOS_UCOS) && ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1))
|
||
struct
|
||
{
|
||
INT8U lock : 1;
|
||
} flag;
|
||
#endif
|
||
struct
|
||
{
|
||
INT8U cache : 1;
|
||
INT8U prefetch : 1;
|
||
} config;
|
||
#if (defined RTOS_UCOS)
|
||
OS_EVENT *sem;
|
||
#endif
|
||
file_cache *cache;
|
||
struct
|
||
{
|
||
INT32U flag;
|
||
#if 1
|
||
FILE *fil;
|
||
FILE *tmp;
|
||
#endif
|
||
} stream;
|
||
} file_provider;
|
||
|
||
#define STREAM_FLAG_FOPEN (1UL << 0)
|
||
|
||
static INT32U FileCacheGet(file_cache **head, const char *store, const char *id, const char *key, char *value, INT32U size, BOOL *isNull)
|
||
{
|
||
file_cache *fc;
|
||
fileprop_cache *pc;
|
||
for (fc = *head; fc != NULL; fc = fc->next)
|
||
{
|
||
if ((strcmp(store, fc->store) == 0) && ((((id == NULL) || (*id == 0)) && ((fc->id == NULL) || (*fc->id == 0))) || ((id != NULL) && (fc->id != NULL) && (strcmp(id, fc->id) == 0))))
|
||
break;
|
||
}
|
||
if (fc == NULL)
|
||
return RET_PROPERTY_NOT_FOUND;
|
||
*isNull = TRUE;
|
||
for (pc = fc->cache; pc != NULL; pc = pc->next)
|
||
{
|
||
if (strcmp(key, pc->key) == 0)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
if (pc->value != NULL)
|
||
{
|
||
INT32U cpLen = pc->size;
|
||
if (cpLen > size - 1)
|
||
{
|
||
cpLen = size - 1;
|
||
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
|
||
}
|
||
*isNull = FALSE;
|
||
strncpy(value, pc->value, cpLen);
|
||
value[cpLen] = 0;
|
||
}
|
||
return ret;
|
||
}
|
||
}
|
||
if (fc->allCache)
|
||
return RET_EXT_NO_ERROR;
|
||
return RET_PROPERTY_NOT_FOUND;
|
||
}
|
||
|
||
static INT32U FileCacheTouch(file_cache **head, const char *store, const char *id, BOOL allCache, file_cache **found)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
file_cache *fc;
|
||
for (fc = *head; fc != NULL; fc = fc->next)
|
||
{
|
||
if ((strcmp(store, fc->store) == 0) && ((((id == NULL) || (*id == 0)) && ((fc->id == NULL) || (*fc->id == 0))) || ((id != NULL) && (fc->id != NULL) && (strcmp(id, fc->id) == 0))))
|
||
break;
|
||
}
|
||
if (fc == NULL)
|
||
{
|
||
BOOL fail = FALSE;
|
||
fc = (file_cache *)malloc_mt(sizeof(file_cache));
|
||
if (fc == NULL)
|
||
fail = TRUE;
|
||
else
|
||
memset(fc, 0, sizeof(file_cache));
|
||
if (!fail)
|
||
{
|
||
INT32U lenStore = strlen(store);
|
||
fc->store = (char *)malloc_mt(lenStore + 1);
|
||
if (fc->store == NULL)
|
||
{
|
||
fail = TRUE;
|
||
}
|
||
else
|
||
{
|
||
strncpy(fc->store, store, lenStore);
|
||
fc->store[lenStore] = 0;
|
||
}
|
||
}
|
||
if (!fail && (id != NULL) && (*id != 0))
|
||
{
|
||
INT32U lenId = strlen(id);
|
||
fc->id = (char *)malloc_mt(lenId + 1);
|
||
if (fc->id == NULL)
|
||
{
|
||
fail = TRUE;
|
||
}
|
||
else
|
||
{
|
||
strncpy(fc->id, id, lenId);
|
||
fc->id[lenId] = 0;
|
||
}
|
||
}
|
||
if (fail)
|
||
{
|
||
if (fc != NULL)
|
||
{
|
||
if (fc->store != NULL)
|
||
free_mt(fc->store);
|
||
if (fc->id != NULL)
|
||
free_mt(fc->id);
|
||
free_mt(fc);
|
||
fc = NULL;
|
||
}
|
||
ret = RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
else
|
||
{
|
||
fc->allCache = allCache;
|
||
fc->next = *head;
|
||
*head = fc;
|
||
}
|
||
}
|
||
if (found != NULL)
|
||
*found = fc;
|
||
return ret;
|
||
}
|
||
|
||
static INT32U FileCacheSet(file_cache **head, const char *store, const char *id, const char *key, const char *value, BOOL allCache)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
file_cache *fc = NULL;
|
||
ret = FileCacheTouch(head, store, id, allCache, &fc);
|
||
if ((ret == RET_EXT_NO_ERROR) && (fc != NULL))
|
||
{
|
||
fileprop_cache *pc;
|
||
fileprop_cache *ptail = NULL;
|
||
for (pc = fc->cache; pc != NULL; ptail = pc, pc = pc->next)
|
||
{
|
||
if (strcmp(key, pc->key) == 0)
|
||
break;
|
||
}
|
||
if (pc == NULL)
|
||
{
|
||
BOOL fail = FALSE;
|
||
pc = (fileprop_cache *)malloc_mt(sizeof(fileprop_cache));
|
||
if (pc == NULL)
|
||
fail = TRUE;
|
||
else
|
||
memset(pc, 0, sizeof(fileprop_cache));
|
||
if (!fail)
|
||
{
|
||
INT32U keyLen = strlen(key);
|
||
pc->key = (char *)malloc_mt(keyLen + 1);
|
||
if (pc->key == NULL)
|
||
{
|
||
fail = TRUE;
|
||
}
|
||
else
|
||
{
|
||
strncpy(pc->key, key, keyLen);
|
||
pc->key[keyLen] = 0;
|
||
}
|
||
}
|
||
if (!fail && (value != NULL))
|
||
{
|
||
pc->size = strlen(value);
|
||
pc->value = (char *)malloc_mt(pc->size + 1);
|
||
if (pc->value == NULL)
|
||
{
|
||
fail = TRUE;
|
||
}
|
||
else
|
||
{
|
||
strncpy(pc->value, value, pc->size);
|
||
pc->value[pc->size] = 0;
|
||
}
|
||
}
|
||
if (fail)
|
||
{
|
||
if (pc != NULL)
|
||
{
|
||
if (pc->key != NULL)
|
||
free_mt(pc->key);
|
||
if (pc->value != NULL)
|
||
free_mt(pc->value);
|
||
free_mt(pc);
|
||
pc = NULL;
|
||
}
|
||
fc->allCache = FALSE;
|
||
ret = RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
else
|
||
{
|
||
pc->next = fc->cache;
|
||
fc->cache = pc;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
BOOL alloc = FALSE;
|
||
if (value == NULL)
|
||
{
|
||
free_mt(pc->key);
|
||
if (pc->value != NULL)
|
||
free_mt(pc->value);
|
||
if (pc == fc->cache)
|
||
fc->cache = pc->next;
|
||
else
|
||
ptail->next = pc->next;
|
||
free_mt(pc);
|
||
}
|
||
else if (pc->value == NULL)
|
||
{
|
||
alloc = TRUE;
|
||
}
|
||
else if (pc->size >= strlen(value))
|
||
{
|
||
strncpy(pc->value, value, strlen(value));
|
||
}
|
||
else
|
||
{
|
||
if (pc->value != NULL)
|
||
free_mt(pc->value);
|
||
pc->value = NULL;
|
||
pc->size = 0;
|
||
alloc = TRUE;
|
||
}
|
||
if (alloc)
|
||
{
|
||
pc->size = strlen(value);
|
||
pc->value = (char *)malloc_mt(pc->size + 1);
|
||
if (pc->value == NULL)
|
||
{
|
||
free_mt(pc->key);
|
||
if (pc == fc->cache)
|
||
fc->cache = pc->next;
|
||
else
|
||
ptail->next = pc->next;
|
||
free_mt(pc);
|
||
fc->allCache = FALSE;
|
||
ret = RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
else
|
||
{
|
||
strncpy(pc->value, value, pc->size);
|
||
pc->value[pc->size] = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static INT32U FileCacheClearLinkList(fileprop_cache *ptr)
|
||
{
|
||
for (; ptr != NULL;)
|
||
{
|
||
fileprop_cache *tmp = ptr;
|
||
ptr = ptr->next;
|
||
free_mt(tmp->key);
|
||
if (tmp->value != NULL)
|
||
free_mt(tmp->value);
|
||
free_mt(tmp);
|
||
}
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
static INT32U FileCacheClear(file_cache **head, const char *store, const char *id)
|
||
{
|
||
file_cache *fc;
|
||
if ((store == NULL) || (*store == 0))
|
||
{
|
||
for (fc = *head; fc != NULL;)
|
||
{
|
||
file_cache *tmp = fc;
|
||
fc = fc->next;
|
||
FileCacheClearLinkList(tmp->cache);
|
||
free_mt(tmp->store);
|
||
if (tmp->id != NULL)
|
||
free_mt(tmp->id);
|
||
free_mt(tmp);
|
||
}
|
||
*head = NULL;
|
||
}
|
||
else if ((id == NULL) || (*id == 0))
|
||
{
|
||
file_cache *ftail = NULL;
|
||
for (fc = *head; fc != NULL;)
|
||
{
|
||
if (strcmp(store, fc->store) == 0)
|
||
{
|
||
file_cache *del = fc;
|
||
FileCacheClearLinkList(fc->cache);
|
||
free_mt(fc->store);
|
||
if (fc->id != NULL)
|
||
free_mt(fc->id);
|
||
if (fc == *head)
|
||
*head = fc->next;
|
||
else
|
||
ftail->next = fc->next;
|
||
fc = fc->next;
|
||
free_mt(del);
|
||
}
|
||
else
|
||
{
|
||
ftail = fc;
|
||
fc = fc->next;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
file_cache *ftail = NULL;
|
||
for (fc = *head; fc != NULL; ftail = fc, fc = fc->next)
|
||
{
|
||
if ((strcmp(store, fc->store) == 0) && ((fc->id != NULL) && (strcmp(id, fc->id) == 0)))
|
||
break;
|
||
}
|
||
if (fc != NULL)
|
||
{
|
||
FileCacheClearLinkList(fc->cache);
|
||
free_mt(fc->store);
|
||
if (fc->id != NULL)
|
||
free_mt(fc->id);
|
||
if (fc == *head)
|
||
*head = fc->next;
|
||
else
|
||
ftail->next = fc->next;
|
||
free_mt(fc);
|
||
}
|
||
}
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
static INT32U INT32U2err(INT32U fres)
|
||
{
|
||
#if 0
|
||
switch (fres)
|
||
{
|
||
case FR_OK:
|
||
return RET_EXT_NO_ERROR;
|
||
case FR_DISK_ERR:
|
||
return RET_FILE_FR_DISK_ERR;
|
||
case FR_INT_ERR:
|
||
return RET_FILE_FR_INT_ERR;
|
||
case FR_NOT_READY:
|
||
return RET_FILE_FR_NOT_READY;
|
||
case FR_NO_FILE:
|
||
return RET_FILE_FR_NO_FILE;
|
||
case FR_NO_PATH:
|
||
return RET_FILE_FR_NO_PATH;
|
||
case FR_INVALID_NAME:
|
||
return RET_FILE_FR_INVALID_NAME;
|
||
case FR_DENIED:
|
||
return RET_FILE_FR_DENIED;
|
||
case FR_EXIST:
|
||
return RET_FILE_FR_EXIST;
|
||
case FR_INVALID_OBJECT:
|
||
return RET_FILE_FR_INVALID_OBJECT;
|
||
case FR_WRITE_PROTECTED:
|
||
return RET_FILE_FR_WRITE_PROTECTED;
|
||
case FR_INVALID_DRIVE:
|
||
return RET_FILE_FR_INVALID_DRIVE;
|
||
case FR_NOT_ENABLED:
|
||
return RET_FILE_FR_NOT_ENABLED;
|
||
case FR_NO_FILESYSTEM:
|
||
return RET_FILE_FR_NO_FILESYSTEM;
|
||
case FR_MKFS_ABORTED:
|
||
return RET_FILE_FR_MKFS_ABORTED;
|
||
case FR_TIMEOUT:
|
||
return RET_FILE_FR_TIMEOUT;
|
||
// case FR_LOCKED:
|
||
// return RET_FILE_FR_LOCKED;
|
||
// case FR_NOT_ENOUGH_CORE:
|
||
// return RET_FILE_FR_NOT_ENOUGH_CORE;
|
||
// case FR_TOO_MANY_OPEN_FILES:
|
||
// return RET_FILE_FR_TOO_MANY_OPEN_FILES;
|
||
// case FR_INVALID_PARAMETER:
|
||
// return RET_FILE_FR_INVALID_PARAMETER;
|
||
}
|
||
return RET_FILE_UNKNOWN;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static void FILE_TEST_RANDOM(INT8U max)
|
||
{
|
||
if ((file_test_random > 0) && (max > 0))
|
||
{
|
||
file_test_random = (rand() % max) + 1;
|
||
printf("[TEST] file_test_random = %d", file_test_random);
|
||
}
|
||
}
|
||
|
||
static void FILE_TEST_RESET(INT8U num)
|
||
{
|
||
#if 0
|
||
if (file_test_random == num)
|
||
{
|
||
printf("[TEST] swReset() called. file_test_random = %d", file_test_random);
|
||
swReset();
|
||
}
|
||
#endif
|
||
}
|
||
|
||
static INT32U f_copy(const char *src, const char *dest)
|
||
{
|
||
#if 0
|
||
FIL filSrc, filDest;
|
||
INT32U fres;
|
||
BYTE *buf;
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
fres = f_open(&filSrc, src, FA_OPEN_EXISTING | FA_READ);
|
||
if (fres != FR_OK)
|
||
return INT32U2err(fres);
|
||
fres = f_open(&filDest, dest, FA_CREATE_ALWAYS | FA_WRITE);
|
||
if (fres != FR_OK)
|
||
{
|
||
f_close(&filSrc);
|
||
return INT32U2err(fres);
|
||
}
|
||
buf = malloc_mt(COPY_BUF_SIZE);
|
||
if (buf == NULL)
|
||
{
|
||
f_close(&filSrc);
|
||
f_close(&filDest);
|
||
return RET_OS_HEAP_FULL;
|
||
}
|
||
for (;;)
|
||
{
|
||
INT32U rsize, wsize;
|
||
fres = f_read(&filSrc, buf, COPY_BUF_SIZE, &rsize);
|
||
if (fres != FR_OK)
|
||
{
|
||
ret = INT32U2err(fres);
|
||
break;
|
||
}
|
||
if (rsize == 0)
|
||
break;
|
||
fres = f_write(&filDest, buf, rsize, &wsize);
|
||
if (rsize != wsize)
|
||
{
|
||
ret = RET_FILE_DISK_FULL;
|
||
break;
|
||
}
|
||
if (fres != FR_OK)
|
||
{
|
||
ret = INT32U2err(fres);
|
||
break;
|
||
}
|
||
}
|
||
free_mt(buf);
|
||
f_close(&filSrc);
|
||
f_close(&filDest);
|
||
return ret;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static INT32U PropWriteLogClear(INT32U providerId)
|
||
{
|
||
#if 0
|
||
INT32U fres;
|
||
char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
snprintf(logname, sizeof(logname), UPDATE_LOG, providerId);
|
||
fres = f_unlink(logname);
|
||
if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH))
|
||
return RET_PROPERTY_FILE_WRITE_ERR;
|
||
return RET_EXT_NO_ERROR;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static INT32U PropWriteLogWrite(INT32U providerId, const char *path)
|
||
{
|
||
#if 0
|
||
FIL fil;
|
||
INT32U fres;
|
||
char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
INT32U wsize;
|
||
if (path == NULL)
|
||
return RET_OS_INVALID_PARAM;
|
||
snprintf(logname, sizeof(logname), UPDATE_LOG, providerId);
|
||
fres = f_open(&fil, logname, FA_CREATE_ALWAYS | FA_WRITE);
|
||
if (fres != FR_OK)
|
||
return INT32U2err(fres);
|
||
fres = f_write(&fil, path, strlen(path), &wsize);
|
||
f_close(&fil);
|
||
if ((fres == FR_OK) && (wsize != strlen(path)))
|
||
return RET_FILE_DISK_FULL;
|
||
return INT32U2err(fres);
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static INT32U PropWriteLogLoad(INT32U providerId, char *path, INT32U size)
|
||
{
|
||
#if 0
|
||
FIL fil;
|
||
INT32U fres;
|
||
INT32U rsize = 0;
|
||
INT32U i;
|
||
char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
if (path == NULL || size == 0)
|
||
return RET_OS_INVALID_PARAM;
|
||
path[0] = '\0';
|
||
snprintf(logname, sizeof(logname), UPDATE_LOG, providerId);
|
||
fres = f_open(&fil, logname, FA_OPEN_EXISTING | FA_READ);
|
||
if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH))
|
||
return RET_EXT_NO_ERROR;
|
||
if (fres != FR_OK)
|
||
return INT32U2err(fres);
|
||
fres = f_read(&fil, path, size, &rsize);
|
||
f_close(&fil);
|
||
if (rsize == size)
|
||
path[size - 1] = '\0';
|
||
for (i = 0; path[i] != '\0'; i++)
|
||
if (path[i] == '\r' || path[i] == '\n')
|
||
{
|
||
path[i] = '\0';
|
||
break;
|
||
}
|
||
if (fres == FR_OK)
|
||
{
|
||
char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
snprintf(filetmp, sizeof(filetmp), "%s.tmp", path);
|
||
fres = f_open(&fil, filetmp, FA_OPEN_EXISTING | FA_READ);
|
||
f_close(&fil);
|
||
if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH))
|
||
{
|
||
fres = FR_OK;
|
||
path[0] = '\0';
|
||
}
|
||
}
|
||
if (fres != FR_OK)
|
||
path[0] = '\0';
|
||
return INT32U2err(fres);
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static INT32U PropWriteLogCommit(INT32U providerId, const char *filename)
|
||
{
|
||
#if 0
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
INT32U fres;
|
||
char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
snprintf(filetmp, sizeof(filetmp), "%s.tmp", filename);
|
||
FILE_TEST_RESET(1);
|
||
fres = f_unlink(filename);
|
||
if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH))
|
||
ret = RET_PROPERTY_FILE_WRITE_ERR;
|
||
FILE_TEST_RESET(2);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
ret = f_copy(filetmp, filename);
|
||
FILE_TEST_RESET(3);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
ret = PropWriteLogClear(providerId);
|
||
FILE_TEST_RESET(4);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
INT32U fres = f_unlink(filetmp);
|
||
if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH))
|
||
ret = RET_PROPERTY_FILE_WRITE_ERR;
|
||
}
|
||
FILE_TEST_RESET(5);
|
||
return ret;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
#if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0))
|
||
static void FormatSHA1sum(char *buf, INT32U lenOfBuf, INT8U *sig, INT32U lenOfSig)
|
||
{
|
||
INT8U i = 0;
|
||
for (i = 0; i < lenOfSig; i++)
|
||
snprintf(&buf[i << 1], (lenOfBuf - (i << 1)), "%02x", sig[i]);
|
||
buf[lenOfBuf - 1] = '\0';
|
||
}
|
||
#endif
|
||
// TODO:启用sha校验
|
||
static INT32U FileStreamChecksum(const char *filename)
|
||
{
|
||
#if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0))
|
||
FIL fil;
|
||
INT8U buf[128];
|
||
INT8U hash[32];
|
||
char sigStr[sizeof(hash) * 2 + 1];
|
||
char sigName[PROPERTY_STORE_MAX + 20];
|
||
sha2_context ctx;
|
||
INT32U fres;
|
||
INT32U br;
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
if ((filename == NULL) || (*filename == 0))
|
||
return RET_EXT_NO_ERROR;
|
||
fres = f_open(&fil, filename, FA_OPEN_EXISTING | FA_READ);
|
||
if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH))
|
||
return RET_EXT_NO_ERROR;
|
||
if (fres != FR_OK)
|
||
return RET_PROPERTY_INVALID_SIGNATURE; // RET_PROPERTY_FILE_OPEN_ERR
|
||
sha2_starts(&ctx, 0);
|
||
// TODO: 加入其他信息校验信息
|
||
for (;;)
|
||
{
|
||
if (f_read(&fil, buf, sizeof(buf), &br) != FR_OK)
|
||
{
|
||
ret = RET_PROPERTY_INVALID_SIGNATURE; // RET_PROPERTY_FILE_READ_ERR
|
||
break;
|
||
}
|
||
if (br == 0)
|
||
break;
|
||
// TODO: 加入加密算法
|
||
sha2_update(&ctx, buf, br);
|
||
}
|
||
f_close(&fil);
|
||
sha2_finish(&ctx, hash);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
return ret;
|
||
snprintf(sigName, sizeof(sigName), "%s.sig", filename);
|
||
fres = f_open(&fil, sigName, FA_OPEN_EXISTING | FA_READ);
|
||
if (fres != FR_OK)
|
||
return RET_PROPERTY_INVALID_SIGNATURE;
|
||
if ((f_read(&fil, sigStr, (sizeof(hash) * 2), &br) != FR_OK) || (br != (sizeof(hash) * 2)))
|
||
ret = RET_PROPERTY_INVALID_SIGNATURE;
|
||
f_close(&fil);
|
||
sigStr[sizeof(hash) * 2] = '\0';
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
char hashStr[sizeof(hash) * 2 + 1];
|
||
FormatSHA1sum(hashStr, sizeof(hashStr), hash, sizeof(hash));
|
||
if (strcmp(hashStr, sigStr) != 0)
|
||
ret = RET_PROPERTY_INVALID_SIGNATURE;
|
||
}
|
||
return ret;
|
||
#else
|
||
return RET_EXT_NO_ERROR;
|
||
#endif
|
||
}
|
||
|
||
static INT32U FileStreamOpen(const char *filename, file_provider *fp)
|
||
{
|
||
#if 0
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
INT32U fres;
|
||
if ((filename == NULL) || (*filename == 0) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
fp->stream.flag = 0;
|
||
fres = f_open(&fp->stream.fil, filename, FA_OPEN_EXISTING | FA_READ);
|
||
if (fres == FR_OK)
|
||
{
|
||
fp->stream.flag |= STREAM_FLAG_FOPEN;
|
||
}
|
||
else if ((fres != FR_NO_FILE) && (fres != FR_NO_PATH))
|
||
{
|
||
ret = RET_PROPERTY_FILE_OPEN_ERR;
|
||
}
|
||
return ret;
|
||
#else
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
INT32U fres;
|
||
if ((filename == NULL) || (*filename == 0) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
fp->stream.flag = 0;
|
||
fp->stream.fil = fopen(filename, "r");
|
||
// printf("file name : %s\n",filename);
|
||
if (fp->stream.fil != NULL)
|
||
{
|
||
// printf("file read ok \n");
|
||
// 读取到文件了
|
||
fp->stream.flag |= STREAM_FLAG_FOPEN;
|
||
}
|
||
else
|
||
{
|
||
ret = RET_PROPERTY_FILE_OPEN_ERR;
|
||
}
|
||
return ret;
|
||
#endif
|
||
}
|
||
|
||
static INT32U FileStreamClose(file_provider *fp)
|
||
{
|
||
#if 0
|
||
if (fp == NULL)
|
||
return RET_OS_INVALID_PARAM;
|
||
if ((fp->stream.flag & STREAM_FLAG_FOPEN) != 0)
|
||
f_close(&fp->stream.fil);
|
||
fp->stream.flag = 0;
|
||
return RET_EXT_NO_ERROR;
|
||
#else
|
||
// 指针检查
|
||
if (fp == NULL)
|
||
return RET_OS_INVALID_PARAM;
|
||
// 关闭文件
|
||
if ((fp->stream.flag & STREAM_FLAG_FOPEN) != 0)
|
||
fclose(fp->stream.fil);
|
||
fp->stream.fil = NULL;
|
||
fp->stream.flag = 0;
|
||
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static INT32U FileStreamGet(char *ch, file_provider *fp)
|
||
{
|
||
#if 0
|
||
if ((ch == NULL) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
if ((fp->stream.flag & STREAM_FLAG_FOPEN) == 0)
|
||
{
|
||
*ch = 0;
|
||
}
|
||
else
|
||
{
|
||
INT32U br;
|
||
if (f_read(&fp->stream.fil, ch, 1, &br) != FR_OK)
|
||
return RET_PROPERTY_FILE_READ_ERR;
|
||
if (br == 0)
|
||
*ch = 0;
|
||
}
|
||
return RET_EXT_NO_ERROR;
|
||
#else
|
||
// 指针检查
|
||
if ((ch == NULL) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
// 检查下文件是否打开
|
||
if ((fp->stream.flag & STREAM_FLAG_FOPEN) == 0)
|
||
{
|
||
// ch = 0 的话,后续程序会直接退出
|
||
*ch = 0;
|
||
}
|
||
else
|
||
{
|
||
*ch = fgetc(fp->stream.fil);
|
||
// 检查是是否读取错误
|
||
if (ferror(fp->stream.fil) != 0)
|
||
{
|
||
*ch = 0;
|
||
}
|
||
}
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static INT32U FileStreamParseLine(BOOL *eof, BOOL *valid, char *lineBuffer, INT32U bufferSize, INT32U *keyIndex, INT32U *keyLen, INT32U *valIndex, INT32U *valLen, file_provider *fp)
|
||
{
|
||
#if 0
|
||
static const INT8U PARSE_STATE_NEW = 0;
|
||
static const INT8U PARSE_STATE_SKIP = 1;
|
||
static const INT8U PARSE_STATE_KEY_READING = 2;
|
||
static const INT8U PARSE_STATE_KEY_FINISHED = 3;
|
||
static const INT8U PARSE_STATE_STRING_TRIM = 4;
|
||
static const INT8U PARSE_STATE_STRING_READING = 5;
|
||
|
||
INT8U state = PARSE_STATE_NEW;
|
||
INT32U ptr = 0;
|
||
BOOL stop = FALSE;
|
||
|
||
if ((eof == NULL) || (valid == NULL) || (lineBuffer == NULL) || (bufferSize == 0) || (keyIndex == NULL) || (keyLen == NULL) || (valIndex == NULL) || (valLen == NULL) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
|
||
*valid = FALSE;
|
||
for (; !stop;)
|
||
{
|
||
char ch = 0;
|
||
INT32U ret = FileStreamGet(&ch, fp);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
return ret;
|
||
if (ch != 0)
|
||
{
|
||
if (ptr < bufferSize - 1)
|
||
{
|
||
lineBuffer[ptr++] = ch;
|
||
}
|
||
else
|
||
{
|
||
if (((ch == '\r') || (ch == '\n')) && (ptr == bufferSize - 1))
|
||
lineBuffer[ptr - 1] = ch;
|
||
state = PARSE_STATE_SKIP;
|
||
*valid = FALSE;
|
||
}
|
||
}
|
||
switch (state)
|
||
{
|
||
case PARSE_STATE_NEW:
|
||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
|
||
{
|
||
*keyIndex = ptr - 1;
|
||
state = PARSE_STATE_KEY_READING;
|
||
}
|
||
else if (ch == ' ' || ch == '\t')
|
||
{
|
||
// do nothing
|
||
}
|
||
else if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else
|
||
{
|
||
state = PARSE_STATE_SKIP;
|
||
}
|
||
break;
|
||
case PARSE_STATE_KEY_READING:
|
||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '.') || (ch == '-') || (ch == '_') || (ch == '[') || (ch == ']'))
|
||
{
|
||
}
|
||
else if (ch == '=')
|
||
{
|
||
*keyLen = ptr - *keyIndex - 1;
|
||
state = PARSE_STATE_STRING_TRIM;
|
||
}
|
||
else if (ch == ' ' || ch == '\t')
|
||
{
|
||
*keyLen = ptr - *keyIndex - 1;
|
||
state = PARSE_STATE_KEY_FINISHED;
|
||
}
|
||
else if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else
|
||
{
|
||
state = PARSE_STATE_SKIP;
|
||
}
|
||
break;
|
||
case PARSE_STATE_KEY_FINISHED:
|
||
if (ch == '=')
|
||
{
|
||
state = PARSE_STATE_STRING_TRIM;
|
||
}
|
||
else if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else if (ch != ' ' && ch != '\t')
|
||
{
|
||
state = PARSE_STATE_SKIP;
|
||
}
|
||
break;
|
||
case PARSE_STATE_STRING_TRIM:
|
||
if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*valIndex = ptr - 1;
|
||
*valLen = 0;
|
||
*valid = TRUE;
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else if (ch != ' ' && ch != '\t')
|
||
{
|
||
*valIndex = ptr - 1;
|
||
*valLen = 1;
|
||
*valid = TRUE;
|
||
state = PARSE_STATE_STRING_READING;
|
||
}
|
||
break;
|
||
case PARSE_STATE_STRING_READING:
|
||
if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else if ((ch != ' ') && (ch != '\t'))
|
||
{
|
||
*valLen = ptr - *valIndex;
|
||
}
|
||
break;
|
||
case PARSE_STATE_SKIP:
|
||
default:
|
||
if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
// state = PARSE_STATE_SKIP;
|
||
break;
|
||
}
|
||
}
|
||
lineBuffer[ptr] = 0;
|
||
return RET_EXT_NO_ERROR;
|
||
#else
|
||
#define PARSE_STATE_NEW 0
|
||
#define PARSE_STATE_SKIP 1
|
||
#define PARSE_STATE_KEY_READING 2
|
||
#define PARSE_STATE_KEY_FINISHED 3
|
||
#define PARSE_STATE_STRING_TRIM 4
|
||
#define PARSE_STATE_STRING_READING 5
|
||
|
||
INT8U state = PARSE_STATE_NEW;
|
||
INT32U ptr = 0;
|
||
BOOL stop = FALSE;
|
||
|
||
if ((eof == NULL) || (valid == NULL) || (lineBuffer == NULL) || (bufferSize == 0) || (keyIndex == NULL) || (keyLen == NULL) || (valIndex == NULL) || (valLen == NULL) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
|
||
*valid = FALSE;
|
||
for (; !stop;)
|
||
{
|
||
char ch = 0;
|
||
INT32U ret = FileStreamGet(&ch, fp);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
return ret;
|
||
if (ch != 0)
|
||
{
|
||
if (ptr < bufferSize - 1)
|
||
{
|
||
lineBuffer[ptr++] = ch;
|
||
}
|
||
else
|
||
{
|
||
if (((ch == '\r') || (ch == '\n')) && (ptr == bufferSize - 1))
|
||
lineBuffer[ptr - 1] = ch;
|
||
state = PARSE_STATE_SKIP;
|
||
*valid = FALSE;
|
||
}
|
||
}
|
||
switch (state)
|
||
{
|
||
case PARSE_STATE_NEW:
|
||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
|
||
{
|
||
*keyIndex = ptr - 1;
|
||
state = PARSE_STATE_KEY_READING;
|
||
}
|
||
else if (ch == ' ' || ch == '\t')
|
||
{
|
||
// do nothing
|
||
}
|
||
else if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else
|
||
{
|
||
state = PARSE_STATE_SKIP;
|
||
}
|
||
break;
|
||
case PARSE_STATE_KEY_READING:
|
||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '.') || (ch == '-') || (ch == '_') || (ch == '[') || (ch == ']'))
|
||
{
|
||
}
|
||
else if (ch == '=')
|
||
{
|
||
*keyLen = ptr - *keyIndex - 1;
|
||
state = PARSE_STATE_STRING_TRIM;
|
||
}
|
||
else if (ch == ' ' || ch == '\t')
|
||
{
|
||
*keyLen = ptr - *keyIndex - 1;
|
||
state = PARSE_STATE_KEY_FINISHED;
|
||
}
|
||
else if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else
|
||
{
|
||
state = PARSE_STATE_SKIP;
|
||
}
|
||
break;
|
||
case PARSE_STATE_KEY_FINISHED:
|
||
if (ch == '=')
|
||
{
|
||
state = PARSE_STATE_STRING_TRIM;
|
||
}
|
||
else if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else if (ch != ' ' && ch != '\t')
|
||
{
|
||
state = PARSE_STATE_SKIP;
|
||
}
|
||
break;
|
||
case PARSE_STATE_STRING_TRIM:
|
||
if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*valIndex = ptr - 1;
|
||
*valLen = 0;
|
||
*valid = TRUE;
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else if (ch != ' ' && ch != '\t')
|
||
{
|
||
*valIndex = ptr - 1;
|
||
*valLen = 1;
|
||
*valid = TRUE;
|
||
state = PARSE_STATE_STRING_READING;
|
||
}
|
||
break;
|
||
case PARSE_STATE_STRING_READING:
|
||
if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
else if ((ch != ' ') && (ch != '\t'))
|
||
{
|
||
*valLen = ptr - *valIndex;
|
||
}
|
||
break;
|
||
case PARSE_STATE_SKIP:
|
||
default:
|
||
if (ch == '\r' || ch == '\n' || ch == 0)
|
||
{
|
||
*eof = (ch == 0);
|
||
stop = TRUE;
|
||
}
|
||
// state = PARSE_STATE_SKIP;
|
||
break;
|
||
}
|
||
}
|
||
lineBuffer[ptr] = 0;
|
||
|
||
#undef PARSE_STATE_NEW
|
||
#undef PARSE_STATE_SKIP
|
||
#undef PARSE_STATE_KEY_READING
|
||
#undef PARSE_STATE_KEY_FINISHED
|
||
#undef PARSE_STATE_STRING_TRIM
|
||
#undef PARSE_STATE_STRING_READING
|
||
return RET_EXT_NO_ERROR;
|
||
#endif
|
||
}
|
||
|
||
static INT32U FileStreamPropertyGet(const char *store, const char *id, const char *key, char *value, INT32U size, BOOL *isNull, file_provider *fp)
|
||
{
|
||
#if 0
|
||
char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
char buffer[PROPERTY_LINE_MAX + 2];
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
#if (defined RTOS_UCOS)
|
||
INT8U osRet = OS_ERR_NONE;
|
||
#endif
|
||
|
||
if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (fp == NULL) || (isNull == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
|
||
if ((id == NULL) || (*id == 0))
|
||
snprintf(filename, sizeof(filename), "0:/conf/%s.conf", store);
|
||
else
|
||
snprintf(filename, sizeof(filename), "0:/conf/%s.%s.conf", store, id);
|
||
|
||
#if (defined RTOS_UCOS)
|
||
OSSemPend(fp->sem, OSmsToTick(1000UL), &osRet);
|
||
if (osRet != OS_ERR_NONE)
|
||
return RET_OS_SYNC_OBJ_FAILED;
|
||
#elif ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1))
|
||
PROP_DISABLE_IRQ();
|
||
if (pp[providerId].flag.lock != 0)
|
||
ret = RET_OS_SYNC_OBJ_FAILED;
|
||
else
|
||
pp[providerId].flag.lock = 1;
|
||
PROP_ENABLE_IRQ();
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
return ret;
|
||
#else
|
||
#error "Target error"
|
||
#endif
|
||
|
||
ret = FileCacheGet(&fp->cache, store, id, key, value, size, isNull);
|
||
if ((ret != RET_EXT_NO_ERROR) && (ret != RET_PROPERTY_OUT_OF_VAL_BUF))
|
||
{
|
||
*isNull = TRUE;
|
||
if ((id == NULL) || (*id == 0)) // global config file, checksum is required.
|
||
ret = FileStreamChecksum(filename);
|
||
else
|
||
ret = RET_EXT_NO_ERROR;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
ret = FileStreamOpen(filename, fp);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
for (;;)
|
||
{
|
||
BOOL eof = FALSE;
|
||
BOOL valid = FALSE;
|
||
INT32U keyIndex = 0;
|
||
INT32U keyLen = 0;
|
||
INT32U valIndex = 0;
|
||
INT32U valLen = 0;
|
||
ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
break;
|
||
if (valid)
|
||
{
|
||
BOOL match = FALSE;
|
||
if ((keyLen == strlen(key)) && (strncmp(&buffer[keyIndex], key, keyLen) == 0))
|
||
{
|
||
if (valLen > size - 1)
|
||
{
|
||
valLen = size - 1;
|
||
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
|
||
}
|
||
*isNull = FALSE;
|
||
strncpy(value, &buffer[valIndex], valLen);
|
||
value[valLen] = 0;
|
||
match = TRUE;
|
||
}
|
||
if (fp->config.cache && (match || fp->config.prefetch))
|
||
{
|
||
buffer[keyIndex + keyLen] = 0;
|
||
buffer[valIndex + valLen] = 0;
|
||
FileCacheSet(&fp->cache, store, id, &buffer[keyIndex], &buffer[valIndex], fp->config.prefetch);
|
||
}
|
||
if (match && !fp->config.prefetch)
|
||
break;
|
||
}
|
||
if (eof)
|
||
break;
|
||
}
|
||
if ((ret == RET_EXT_NO_ERROR) && fp->config.prefetch)
|
||
{
|
||
file_cache *cache = NULL;
|
||
FileCacheTouch(&fp->cache, store, id, TRUE, &cache);
|
||
if (cache != NULL)
|
||
cache->allCache = TRUE;
|
||
}
|
||
}
|
||
FileStreamClose(fp);
|
||
}
|
||
PROP_UNLOCK(*fp);
|
||
return ret;
|
||
#else
|
||
char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
char buffer[PROPERTY_LINE_MAX + 2];
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (fp == NULL) || (isNull == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
|
||
if ((id == NULL) || (*id == 0))
|
||
snprintf(filename, sizeof(filename), "%s/%s.conf", config_path, store);
|
||
|
||
ret = FileCacheGet(&fp->cache, store, id, key, value, size, isNull);
|
||
if ((ret != RET_EXT_NO_ERROR) && (ret != RET_PROPERTY_OUT_OF_VAL_BUF))
|
||
{
|
||
*isNull = TRUE;
|
||
// TODO:
|
||
#if 0
|
||
if ((id == NULL) || (*id == 0)) // global config file, checksum is required.
|
||
ret = FileStreamChecksum(filename);
|
||
|
||
else
|
||
ret = RET_EXT_NO_ERROR;
|
||
#else
|
||
ret = RET_EXT_NO_ERROR;
|
||
#endif
|
||
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
// 打开文件
|
||
ret = FileStreamOpen(filename, fp);
|
||
// printf("ret = %d\n", ret);
|
||
}
|
||
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
#if 0
|
||
//逻辑重写
|
||
for (;;)
|
||
{
|
||
BOOL eof = FALSE;
|
||
BOOL valid = FALSE;
|
||
INT32U keyIndex = 0;
|
||
INT32U keyLen = 0;
|
||
INT32U valIndex = 0;
|
||
INT32U valLen = 0;
|
||
// 读取单条
|
||
ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
break;
|
||
if (valid)
|
||
{
|
||
BOOL match = FALSE;
|
||
if ((keyLen == strlen(key)) && (strncmp(&buffer[keyIndex], key, keyLen) == 0))
|
||
{
|
||
if (valLen > size - 1)
|
||
{
|
||
valLen = size - 1;
|
||
ret = RET_PROPERTY_OUT_OF_VAL_BUF;
|
||
}
|
||
*isNull = FALSE;
|
||
strncpy(value, &buffer[valIndex], valLen);
|
||
value[valLen] = 0;
|
||
match = TRUE;
|
||
}
|
||
if (fp->config.cache && (match || fp->config.prefetch))
|
||
{
|
||
buffer[keyIndex + keyLen] = 0;
|
||
buffer[valIndex + valLen] = 0;
|
||
FileCacheSet(&fp->cache, store, id, &buffer[keyIndex], &buffer[valIndex], fp->config.prefetch);
|
||
}
|
||
if (match && !fp->config.prefetch)
|
||
break;
|
||
}
|
||
if (eof)
|
||
break;
|
||
}
|
||
#else
|
||
while (1)
|
||
{
|
||
char temp[100];
|
||
void *result = fgets(temp, sizeof(temp), fp->stream.fil);
|
||
if (result != NULL)
|
||
{
|
||
// printf("%s\n", temp);
|
||
// 搜索到正常的头部
|
||
if ((temp[0] >= 'a' && temp[0] <= 'z') || (temp[0] >= 'A' && temp[0] <= 'Z'))
|
||
{
|
||
// 比对key的情况,key必须顶格写
|
||
int i = 0;
|
||
int result = 1;
|
||
while (key[i] != '\0')
|
||
{
|
||
if (temp[i] != key[i])
|
||
{
|
||
result = 0;
|
||
break;
|
||
}
|
||
if (temp[i] == '=')
|
||
{
|
||
result = 0;
|
||
break;
|
||
}
|
||
i++;
|
||
}
|
||
// 防守配置文件里面的key更长,但是后面不相符的情况
|
||
if (temp[i] != '=')
|
||
{
|
||
result = 0;
|
||
}
|
||
//截断字符串
|
||
temp[i] = '\0';
|
||
// printf("result : %d ; key = %s ; serch = %s\n", result, key, temp);
|
||
// 找到目标
|
||
if (result == 1)
|
||
{
|
||
// 将值拷贝出去
|
||
*isNull = FALSE;
|
||
i++;
|
||
int j = 0;
|
||
while (1)
|
||
{
|
||
|
||
value[j] = temp[i];
|
||
j++;
|
||
i++;
|
||
if (temp[i] == ' ' || temp[i] == '\r' || temp[i] == '\t' || temp[i] == '\n')
|
||
{
|
||
break;
|
||
}
|
||
if (j >= (size - 1))
|
||
{
|
||
// 给的缓存太小了,报个错
|
||
return RET_PROPERTY_OUT_OF_VAL_BUF;
|
||
}
|
||
}
|
||
value[j] = '\0';
|
||
printf("get value = %s\n", value);
|
||
// 设置chache
|
||
if (fp->config.cache && (fp->config.prefetch))
|
||
{
|
||
FileCacheSet(&fp->cache, store, id, temp, value, fp->config.prefetch);
|
||
}
|
||
}
|
||
}
|
||
// 说明读到尾部了
|
||
if (feof(fp->stream.fil) == 1)
|
||
{
|
||
// printf("file end\n");
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 读取失败,退出循环
|
||
// printf("file read error\n");
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
if ((ret == RET_EXT_NO_ERROR) && fp->config.prefetch)
|
||
{
|
||
file_cache *cache = NULL;
|
||
FileCacheTouch(&fp->cache, store, id, TRUE, &cache);
|
||
if (cache != NULL)
|
||
cache->allCache = TRUE;
|
||
}
|
||
}
|
||
FileStreamClose(fp);
|
||
}
|
||
return ret;
|
||
#endif
|
||
}
|
||
|
||
static INT32U FileStreamPropertySet(const char *store, const char *id, property_string_item *list, INT32U count, file_provider *fp)
|
||
{
|
||
#if 0
|
||
char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 20];
|
||
char buffer[PROPERTY_LINE_MAX + 2];
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
#if (defined RTOS_UCOS)
|
||
INT8U osRet = OS_ERR_NONE;
|
||
#endif
|
||
BOOL newLine = FALSE;
|
||
BOOL changed = FALSE;
|
||
INT32U idx;
|
||
|
||
if ((store == NULL) || (*store == 0) || (list == NULL) || (count == 0) || (fp == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
if ((id == NULL) || (*id == 0))
|
||
return RET_PROPERTY_INVALID_STORE_ID;
|
||
for (idx = 0; idx < count; idx++)
|
||
{
|
||
if ((list[idx].key == NULL) || (*list[idx].key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
list[idx].success = 0;
|
||
}
|
||
|
||
snprintf(filename, sizeof(filename), "%s/%s.%s.conf", config_path, store, id);
|
||
snprintf(filetmp, sizeof(filetmp), "%s/%s.%s.conf.tmp", config_path, store, id);
|
||
FILE_TEST_RANDOM(8);
|
||
|
||
if (f_open(&fp->stream.tmp, filetmp, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
|
||
ret = RET_PROPERTY_FILE_OPEN_ERR;
|
||
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
ret = FileStreamOpen(filename, fp);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
for (;;)
|
||
{
|
||
BOOL skip = FALSE;
|
||
BOOL eof = FALSE;
|
||
BOOL valid = FALSE;
|
||
INT32U keyIndex = 0;
|
||
INT32U keyLen = 0;
|
||
INT32U valIndex = 0;
|
||
INT32U valLen = 0;
|
||
INT32U bw;
|
||
char lastCh;
|
||
ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp);
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
break;
|
||
bw = strlen(buffer);
|
||
lastCh = ((bw > 0) ? buffer[bw - 1] : '\0');
|
||
if ((lastCh != '\r') && (lastCh != '\n') && (bw > 0))
|
||
newLine = TRUE;
|
||
if (valid)
|
||
{
|
||
for (idx = 0; idx < count; idx++)
|
||
{
|
||
if (list[idx].success)
|
||
continue;
|
||
if ((keyLen != strlen(list[idx].key)) || (strncmp(&buffer[keyIndex], list[idx].key, keyLen) != 0))
|
||
continue;
|
||
if (list[idx].value == NULL)
|
||
{
|
||
skip = TRUE;
|
||
}
|
||
else
|
||
{
|
||
if ((lastCh == '\r') || (lastCh == '\n'))
|
||
snprintf(buffer, sizeof(buffer), "%s=%s%c", list[idx].key, list[idx].value, lastCh);
|
||
else
|
||
snprintf(buffer, sizeof(buffer), "%s=%s", list[idx].key, list[idx].value);
|
||
bw = strlen(buffer);
|
||
}
|
||
if (fp->config.cache)
|
||
FileCacheSet(&fp->cache, store, id, list[idx].key, list[idx].value, FALSE);
|
||
list[idx].success = 1;
|
||
changed = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if (!skip)
|
||
{
|
||
if (f_write(&fp->stream.tmp, buffer, bw, &bw) != FR_OK)
|
||
{
|
||
ret = RET_PROPERTY_FILE_WRITE_ERR;
|
||
break;
|
||
}
|
||
}
|
||
if (eof)
|
||
break;
|
||
}
|
||
}
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
for (idx = 0; idx < count; idx++)
|
||
{
|
||
INT32U bw;
|
||
if (list[idx].success)
|
||
continue;
|
||
if (list[idx].value == NULL)
|
||
{
|
||
list[idx].success = 1;
|
||
continue;
|
||
}
|
||
if (newLine)
|
||
{
|
||
newLine = FALSE;
|
||
bw = strlen("\r\n");
|
||
if (f_write(&fp->stream.tmp, "\r\n", bw, &bw) != FR_OK)
|
||
{
|
||
ret = RET_PROPERTY_FILE_WRITE_ERR;
|
||
break;
|
||
}
|
||
}
|
||
snprintf(buffer, sizeof(buffer), "%s=%s\r\n", list[idx].key, list[idx].value);
|
||
bw = strlen(buffer);
|
||
if (f_write(&fp->stream.tmp, buffer, bw, &bw) != 0)
|
||
{
|
||
ret = RET_PROPERTY_FILE_WRITE_ERR;
|
||
break;
|
||
}
|
||
if (fp->config.cache)
|
||
FileCacheSet(&fp->cache, store, id, list[idx].key, list[idx].value, FALSE);
|
||
list[idx].success = 1;
|
||
changed = TRUE;
|
||
}
|
||
}
|
||
FileStreamClose(fp);
|
||
f_close(&fp->stream.tmp);
|
||
// a. 将修改后的配置写入*.conf.tmp
|
||
// b. 将字符串"*.conf"写入update.log
|
||
// c. 删除*.conf
|
||
// d. 复制*.conf.tmp-> *.conf
|
||
// e. 删除update.log
|
||
// f. 删除 *.conf.tmp
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
ret = PropWriteLogWrite(0, filename);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
PropWriteLogCommit(0, filename);
|
||
}
|
||
if (changed && (ret != RET_EXT_NO_ERROR))
|
||
FileCacheClear(&fp->cache, store, id);
|
||
|
||
PROP_UNLOCK(*fp);
|
||
|
||
if (ret != RET_EXT_NO_ERROR)
|
||
{
|
||
for (idx = 0; idx < count; idx++)
|
||
list[idx].success = 0;
|
||
}
|
||
|
||
return ret;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
/** function comment
|
||
* @description:
|
||
* @param {char} *store
|
||
* @param {char} *key
|
||
* @param {char} *id 看上去没有用,直接用的NULL
|
||
* @param {char} *value
|
||
* @param {INT32U} sizeOfValue
|
||
* @param {BOOL} *isLocal
|
||
* @param {void} *obj
|
||
* @return {*}
|
||
*/
|
||
static INT32U FilePropertyGet(const char *store, const char *key, const char *id, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj)
|
||
{
|
||
BOOL isNull = TRUE;
|
||
INT32U ret = RET_PROPERTY_NOT_FOUND;
|
||
file_provider *fp = (file_provider *)obj;
|
||
if (fp == NULL)
|
||
return RET_OS_INVALID_PARAM;
|
||
if (isLocal != NULL)
|
||
*isLocal = FALSE;
|
||
// id在实际应用中没有找到
|
||
if ((id != NULL) && (*id != 0))
|
||
{
|
||
ret = FileStreamPropertyGet(store, id, key, value, sizeOfValue, &isNull, fp);
|
||
if ((ret == RET_EXT_NO_ERROR) && isNull)
|
||
ret = RET_PROPERTY_NOT_FOUND;
|
||
if ((ret == RET_EXT_NO_ERROR) && (isLocal != NULL))
|
||
*isLocal = TRUE;
|
||
}
|
||
|
||
if (ret == RET_PROPERTY_NOT_FOUND)
|
||
{
|
||
ret = FileStreamPropertyGet(store, NULL, key, value, sizeOfValue, &isNull, fp);
|
||
if ((ret == RET_EXT_NO_ERROR) && isNull)
|
||
ret = RET_PROPERTY_NOT_FOUND;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static INT32U FilePropertySet(const char *store, const char *id, property_string_item *list, INT32U count, void *obj)
|
||
{
|
||
|
||
file_provider *fp = (file_provider *)obj;
|
||
if (fp == NULL)
|
||
return RET_OS_INVALID_PARAM;
|
||
if ((id != NULL) && (*id != 0))
|
||
return FileStreamPropertySet(store, id, list, count, fp);
|
||
else
|
||
return RET_PROPERTY_INVALID_STORE_ID;
|
||
}
|
||
|
||
static INT32U FilePropertyClear(const char *store, const char *id, void *obj)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
|
||
file_provider *fp = (file_provider *)obj;
|
||
|
||
if (fp == NULL)
|
||
return RET_OS_INVALID_PARAM;
|
||
|
||
if (!fp->config.cache)
|
||
return RET_EXT_NO_ERROR;
|
||
if ((id == NULL) || (*id == 0))
|
||
id = NULL;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
ret = FileCacheClear(&fp->cache, store, id);
|
||
|
||
return ret;
|
||
}
|
||
|
||
static INT32U FilePropertyInit(INT32U providerId, const PropertyInitParam *param)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
file_provider *fp = NULL;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
fp = (file_provider *)malloc_mt(sizeof(file_provider));
|
||
if (fp == NULL)
|
||
ret = RET_PROPERTY_HEAP_FULL;
|
||
}
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
char storename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16];
|
||
INT32U ret2 = RET_EXT_NO_ERROR;
|
||
memset(fp, 0, sizeof(file_provider));
|
||
fp->config.cache = param->config.cache;
|
||
fp->config.prefetch = (param->config.cache && param->config.prefetch);
|
||
fp->cache = NULL;
|
||
pp[providerId].get = FilePropertyGet;
|
||
pp[providerId].set = FilePropertySet;
|
||
pp[providerId].clear = FilePropertyClear;
|
||
pp[providerId].obj = fp;
|
||
pp[providerId].flag.cache = param->config.cache;
|
||
pp[providerId].flag.init = 1;
|
||
#if 0 // 意义不明,没有storename
|
||
ret2 = PropWriteLogLoad(providerId, storename, sizeof(storename));
|
||
if ((ret2 == RET_EXT_NO_ERROR) && (storename[0] != '\0'))
|
||
{
|
||
printf("PropWriteLogCommit(providerId=%d, storename=%s)\n\r", providerId, storename);
|
||
PropWriteLogCommit(providerId, storename);
|
||
}
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
if (fp != NULL)
|
||
free_mt(fp);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
#endif
|
||
|
||
#if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0))
|
||
|
||
/**************************************************************
|
||
* Remote property provider
|
||
*************************************************************
|
||
*/
|
||
|
||
typedef struct
|
||
{
|
||
INT32U destId;
|
||
} remote_provider;
|
||
|
||
static INT32U RemotePropertyGet(const char *store, const char *key, const char *id, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj)
|
||
{
|
||
INT8U outBuf[PROPERTY_LINE_MAX + sizeof(INT32U)];
|
||
INT8U *inBuf;
|
||
INT8U *ptr;
|
||
INT32U sizeOfIn;
|
||
INT32U sizeOfOut;
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (value == NULL) || (obj == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
sizeOfIn = strlen(store) + strlen(key) + 3;
|
||
if (id != NULL)
|
||
sizeOfIn += strlen(id);
|
||
inBuf = (INT8U *)malloc_mt(sizeOfIn);
|
||
if (inBuf == NULL)
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
ptr = inBuf;
|
||
memcpy(ptr, store, (strlen(store) + 1));
|
||
ptr += (strlen(store) + 1);
|
||
if (id == NULL)
|
||
{
|
||
*ptr = 0;
|
||
ptr++;
|
||
}
|
||
else
|
||
{
|
||
memcpy(ptr, id, (strlen(id) + 1));
|
||
ptr += (strlen(id) + 1);
|
||
}
|
||
memcpy(ptr, key, (strlen(key) + 1));
|
||
sizeOfOut = (PROPERTY_LINE_MAX + sizeof(INT32U));
|
||
ret = bus_host_execute(((remote_provider *)obj)->destId, 2, CMD_mgrGetProp, inBuf, sizeOfIn, outBuf, &sizeOfOut, NULL, NULL, NULL, NULL);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
if ((sizeOfOut > sizeof(INT32U)) && (outBuf[sizeOfOut - 1] == '\0'))
|
||
{
|
||
if (isLocal != NULL)
|
||
*isLocal = (((outBuf[0] & 0x01) == 0) ? FALSE : TRUE);
|
||
strncpy(value, (const char *)&outBuf[sizeof(INT32U)], sizeOfValue);
|
||
value[sizeOfValue - 1] = 0;
|
||
}
|
||
else
|
||
{
|
||
ret = RET_BUS_INVALID_RET_FORMAT;
|
||
}
|
||
}
|
||
free_mt(inBuf);
|
||
return ret;
|
||
}
|
||
|
||
static INT32U RemotePropertySet(const char *store, const char *id, property_string_item *list, INT32U count, void *obj)
|
||
{
|
||
INT32U i;
|
||
INT8U *inBuf;
|
||
INT8U *ptr;
|
||
INT32U sizeOfIn;
|
||
INT32U sizeOfOut = 0;
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
if ((store == NULL) || (*store == 0) || (list == NULL) || (count == 0) || (obj == NULL))
|
||
return RET_OS_INVALID_PARAM;
|
||
if (count > 0xff)
|
||
return RET_PROPERTY_SETP_LIST_EXCEED_MAX;
|
||
sizeOfIn = (strlen(store) + 2);
|
||
if ((id != NULL) && (*id != 0))
|
||
sizeOfIn += strlen(id);
|
||
sizeOfIn += sizeof(INT8U);
|
||
for (i = 0; i < count; i++)
|
||
{
|
||
if ((list[i].key == NULL) || (*list[i].key == 0))
|
||
return RET_OS_INVALID_PARAM;
|
||
sizeOfIn += sizeof(INT8U);
|
||
sizeOfIn += (strlen(list[i].key) + 2);
|
||
if ((list[i].value != NULL) && (*list[i].value != 0))
|
||
sizeOfIn += strlen(list[i].value);
|
||
}
|
||
inBuf = (INT8U *)malloc_mt(sizeOfIn);
|
||
if (inBuf == NULL)
|
||
return RET_PROPERTY_HEAP_FULL;
|
||
ptr = inBuf;
|
||
memcpy(ptr, store, (strlen(store) + 1));
|
||
ptr += (strlen(store) + 1);
|
||
if (id == NULL)
|
||
{
|
||
*ptr = 0;
|
||
ptr++;
|
||
}
|
||
else
|
||
{
|
||
memcpy(ptr, id, (strlen(id) + 1));
|
||
ptr += (strlen(id) + 1);
|
||
}
|
||
*ptr = (count & 0xff);
|
||
ptr++;
|
||
for (i = 0; i < count; i++)
|
||
{
|
||
list[i].success = 0;
|
||
if (list[i].value == NULL)
|
||
*ptr = 0x01; // clear property
|
||
else
|
||
*ptr = 0x00; // set property
|
||
ptr++;
|
||
memcpy(ptr, list[i].key, (strlen(list[i].key) + 1));
|
||
ptr += (strlen(list[i].key) + 1);
|
||
if (list[i].value == NULL)
|
||
{
|
||
*ptr = 0;
|
||
ptr++;
|
||
}
|
||
else
|
||
{
|
||
memcpy(ptr, list[i].value, (strlen(list[i].value) + 1));
|
||
ptr += (strlen(list[i].value) + 1);
|
||
}
|
||
}
|
||
ret = bus_host_execute(((remote_provider *)obj)->destId, 2, CMD_mgrSetPropL, inBuf, sizeOfIn, NULL, &sizeOfOut, NULL, NULL, NULL, NULL);
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
for (i = 0; i < count; i++)
|
||
list[i].success = 0;
|
||
}
|
||
free_mt(inBuf);
|
||
return ret;
|
||
}
|
||
|
||
static INT32U RemotePropertyClear(const char *store, const char *id, void *obj)
|
||
{
|
||
// RemotePropertyClear(), 远端缓存不需要客户端清除, 由远端根据实际情况自行决定
|
||
return RET_EXT_NO_ERROR;
|
||
}
|
||
|
||
static INT32U RemotePropertyInit(INT32U providerId, const PropertyInitParam *param)
|
||
{
|
||
INT32U ret = RET_EXT_NO_ERROR;
|
||
remote_provider *rp = (remote_provider *)malloc_mt(sizeof(remote_provider));
|
||
if (rp == NULL)
|
||
ret = RET_PROPERTY_HEAP_FULL;
|
||
if (ret == RET_EXT_NO_ERROR)
|
||
{
|
||
memset(rp, 0, sizeof(remote_provider));
|
||
rp->destId = param->destId;
|
||
pp[providerId].get = RemotePropertyGet;
|
||
pp[providerId].set = RemotePropertySet;
|
||
pp[providerId].clear = RemotePropertyClear;
|
||
pp[providerId].obj = rp;
|
||
pp[providerId].flag.cache = param->config.cache;
|
||
pp[providerId].flag.init = 1;
|
||
}
|
||
else
|
||
{
|
||
if (rp != NULL)
|
||
free_mt(rp);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
#endif
|
||
|
||
#if 1
|
||
// store name
|
||
static char propStoreSystem[40] = "0x1820_system";
|
||
static char propStorePanel[40] = "0x1820_0x0000_panel";
|
||
static char propStoreTarget[40] = "0x1820_0x0000_target";
|
||
static char propStorePipette[40] = "0x1820_0x0000_pipette";
|
||
static char propStoreTip[40] = "0x1820_0x0000_tip";
|
||
static char propStoreContainer[40] = "0x1820_0x0000_container";
|
||
static char propStoreMotor[40] = "0x1820_0x0000_motor";
|
||
static char propStoreDispense[40] = "0x1820_0x0000_dispense";
|
||
static char propStoreDevMapping[40] = "0x1820_0x0000_dm";
|
||
static char propStoreRoute[40] = "0x1820_0x0000_route";
|
||
static char propStoreDiv[40] = "0x1820_0x0000_div";
|
||
static char propStoreModule[40] = "0x1820_0x0000_module";
|
||
static char propStoreWash[40] = "0x1820_0x0000_wash";
|
||
static char propStoreRea[40] = "0x1820_0x0000_reagentplate";
|
||
const char *GetStoreName(const char *store)
|
||
{
|
||
if (store == NULL)
|
||
return NULL;
|
||
if (strcmp(store, "motor") == 0)
|
||
return propStoreMotor;
|
||
if (strcmp(store, "panel") == 0)
|
||
return propStorePanel;
|
||
if (strcmp(store, "target") == 0)
|
||
return propStoreTarget;
|
||
if (strcmp(store, "pipette") == 0)
|
||
return propStorePipette;
|
||
if (strcmp(store, "tip") == 0)
|
||
return propStoreTip;
|
||
if (strcmp(store, "container") == 0)
|
||
return propStoreContainer;
|
||
if (strcmp(store, "dispense") == 0)
|
||
return propStoreDispense;
|
||
if (strcmp(store, "module") == 0)
|
||
return propStoreModule;
|
||
if (strcmp(store, "dm") == 0)
|
||
return propStoreDevMapping;
|
||
if (strcmp(store, "route") == 0)
|
||
return propStoreRoute;
|
||
if (strcmp(store, "div") == 0)
|
||
return propStoreDiv;
|
||
if (strcmp(store, "system") == 0)
|
||
return propStoreSystem;
|
||
if (strcmp(store, "wash") == 0)
|
||
return propStoreWash;
|
||
return NULL;
|
||
}
|
||
|
||
//unit test
|
||
int main(void)
|
||
{
|
||
INT32U retCode = RET_EXT_NO_ERROR;
|
||
PropertyInitParam param;
|
||
param.config.cache = 1;
|
||
param.config.prefetch = 1;
|
||
param.id = 0;
|
||
param.type = PropertyTypeFS;
|
||
PropertyInit(0, ¶m);
|
||
INT32U ret = 0;
|
||
INT32U val = GetUnsigned(0, "0x1820_0x0000_container", "Container0.Bottom", 0, 0, &ret, NULL);
|
||
printf("%d,%d\n", val, ret);
|
||
val = GetUnsigned(0, "0x1820_0x0000_container", "Container0.Bottom", 0, 0, &ret, NULL);
|
||
printf("%d,%d\n", val, ret);
|
||
}
|
||
|
||
|
||
|
||
#endif |