/* * Copyright (C) 2015-2018 Alibaba Group Holding Limited */ #include "linkkit/infra/infra_config.h" #ifdef INFRA_JSON_PARSER #include #include #include #include #include "linkkit/infra/infra_types.h" #include "linkkit/infra/infra_json_parser.h" #include "linkkit/wrappers/wrappers.h" #ifdef INFRA_LOG #include "linkkit/infra/infra_log.h" #define jparser_debug(...) log_debug("jparser", __VA_ARGS__) #else #define jparser_debug(...) \ do { \ HAL_Printf(__VA_ARGS__); \ HAL_Printf("\r\n"); \ } while (0) #endif #ifdef INFRA_MEM_STATS #include "linkkit/infra/infra_mem_stats.h" #define jparser_malloc(size) LITE_malloc(size, MEM_MAGIC, "jparser") #define jparser_free(ptr) LITE_free(ptr) #else #define jparser_malloc(size) HAL_Malloc(size) #define jparser_free(ptr) \ { \ HAL_Free((void *)ptr); \ ptr = NULL; \ } #endif char *json_get_object(int type, char *str, char *str_end) { char *pos = NULL; char ch = (type == JOBJECT) ? '{' : '['; if (!str || !str_end) { return NULL; } while (str != NULL && *str != 0 && str < str_end) { if (*str == ' ') { str++; continue; } pos = (*str == ch) ? str : NULL; break; } return pos; } char *json_get_next_object(int type, char *str, char *str_end, char **key, int *key_len, char **val, int *val_len, int *val_type) { char JsonMark[JTYPEMAX][2] = { { '\"', '\"' }, { '{', '}' }, { '[', ']' }, { '0', ' ' } }; int iMarkDepth = 0, iValueType = JNONE, iNameLen = 0, iValueLen = 0, iStringDepth = 0; char *p_cName = 0, *p_cValue = 0, *p_cPos = str; if (type == JOBJECT) { /* Get Key */ p_cPos = strchr(p_cPos, '\"'); if (!p_cPos) { goto do_exit; } p_cName = ++p_cPos; p_cPos = strchr(p_cPos, '\"'); if (!p_cPos) { goto do_exit; } iNameLen = p_cPos - p_cName; /* Get Value */ p_cPos = strchr(p_cPos, ':'); } while (p_cPos && *p_cPos && p_cPos < str_end) { if (*p_cPos == '\"') { iValueType = JSTRING; p_cValue = ++p_cPos; break; } else if (*p_cPos == '{') { iValueType = JOBJECT; p_cValue = p_cPos++; break; } else if (*p_cPos == '[') { iValueType = JARRAY; p_cValue = p_cPos++; break; } else if ((*p_cPos == '-') || (*p_cPos >= '0' && *p_cPos <= '9')) { iValueType = JNUMBER; p_cValue = p_cPos++; break; } else if (*p_cPos == 't' || *p_cPos == 'T' || *p_cPos == 'f' || *p_cPos == 'F') { iValueType = JBOOLEAN; p_cValue = p_cPos; break; } p_cPos++; } while (p_cPos && *p_cPos && p_cPos < str_end && iValueType > JNONE) { if (iValueType == JBOOLEAN) { int len = strlen(p_cValue); if ((*p_cValue == 't' || *p_cValue == 'T') && len >= 4 && (!strncmp(p_cValue, "true", 4) || !strncmp(p_cValue, "TRUE", 4))) { iValueLen = 4; p_cPos = p_cValue + iValueLen; break; } else if ((*p_cValue == 'f' || *p_cValue == 'F') && len >= 5 && (!strncmp(p_cValue, "false", 5) || !strncmp(p_cValue, "FALSE", 5))) { iValueLen = 5; p_cPos = p_cValue + iValueLen; break; } } else if (iValueType == JNUMBER) { if ((*p_cPos < '0' || *p_cPos > '9') && (*p_cPos != '.') && (*p_cPos != '+') && (*p_cPos != '-') && ((*p_cPos != 'e')) && (*p_cPos != 'E')) { iValueLen = p_cPos - p_cValue; break; } } else if (iValueType == JSTRING) { if (*p_cPos == '\"') { iValueLen = p_cPos - p_cValue; break; } } else if (*p_cPos == JsonMark[iValueType][1]) { if (iStringDepth == 0) { if (iMarkDepth == 0) { iValueLen = p_cPos - p_cValue + 1; p_cPos++; break; } else { iMarkDepth--; } } } else if (*p_cPos == JsonMark[iValueType][0]) { if (iStringDepth == 0) { iMarkDepth++; } } else if (*p_cPos == '\"') { if (iStringDepth) { iStringDepth = 0; } else { iStringDepth = 1; } } p_cPos++; } if (type == JOBJECT) { if ((p_cName + iNameLen) > str_end) { goto do_exit; } *key = p_cName; *key_len = iNameLen; } if ((p_cValue + iValueLen) > str_end) { goto do_exit; } *val = p_cValue; *val_len = iValueLen; *val_type = iValueType; if (iValueType == JSTRING) { return p_cValue + iValueLen + 1; } else { return p_cValue + iValueLen; } do_exit: *val = NULL; *val_len = 0; *key = NULL; *key_len = 0; return NULL; } int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData) { char *pos = 0, *key = 0, *val = 0; int klen = 0, vlen = 0, vtype = 0; int ret = JSON_RESULT_ERR; if (p_cJsonStr == NULL || iStrLen == 0 || pfnCB == NULL) { return ret; } json_object_for_each_kv(p_cJsonStr, iStrLen, pos, key, klen, val, vlen, vtype) { if (key && klen && val && vlen) { ret = JSON_RESULT_OK; if (JSON_PARSE_FINISH == pfnCB(key, klen, val, vlen, vtype, p_CBData)) { break; } } } return ret; } int json_get_value_by_name_cb(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType, void *p_CBData) { JSON_NV *p_stNameValue = (JSON_NV *)p_CBData; #ifdef JSON_DEBUG int i; if (p_cName) { jparser_debug("Name:"); for (i = 0; i < iNameLen; i++) { jparser_debug("%c", *(p_cName + i)); } } if (p_cValue) { jparser_debug("Value:"); for (i = 0; i < iValueLen; i++) { jparser_debug("%c", *(p_cValue + i)); } } #endif if ((iNameLen == p_stNameValue->nLen) && !strncmp(p_cName, p_stNameValue->pN, p_stNameValue->nLen)) { p_stNameValue->pV = p_cValue; p_stNameValue->vLen = iValueLen; p_stNameValue->vType = iValueType; return JSON_PARSE_FINISH; } else { return JSON_PARSE_OK; } } char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType) { JSON_NV stNV; memset(&stNV, 0, sizeof(stNV)); stNV.pN = p_cName; stNV.nLen = strlen(p_cName); if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) { if (p_iValueLen) { *p_iValueLen = stNV.vLen; } if (p_iValueType) { *p_iValueType = stNV.vType; } } return stNV.pV; } char *json_get_value_by_name_len(char *p_cJsonStr, int iStrLen, char *p_cName, int p_cNameLen, int *p_iValueLen, int *p_iValueType) { JSON_NV stNV; memset(&stNV, 0, sizeof(stNV)); stNV.pN = p_cName; stNV.nLen = p_cNameLen; if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) { if (p_iValueLen) { *p_iValueLen = stNV.vLen; } if (p_iValueType) { *p_iValueType = stNV.vType; } } return stNV.pV; } char *LITE_json_value_of(char *key, char *src, ...) { char *value = NULL; char *ret = NULL; char *delim = NULL; char *key_iter; char *key_next; char *src_iter; int key_len; int value_len = -1; int src_iter_len; if (NULL == key || NULL == src) { return NULL; } #if WITH_MEM_STATS_PER_MODULE { char *module_name = NULL; int magic = 0; va_list ap; va_start(ap, src); magic = va_arg(ap, int); if (MEM_MAGIC == magic) { module_name = va_arg(ap, char *); } va_end(ap); } #endif src_iter = src; src_iter_len = strlen(src_iter); key_iter = key; do { delim = strchr(key_iter, '.'); if (delim != NULL) { key_len = delim - key_iter; key_next = key_iter; value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); if (value == NULL) { return NULL; } src_iter = value; src_iter_len = value_len; key_iter = delim + 1; } } while (delim); key_len = strlen(key_iter); key_next = key_iter; value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); if (NULL == value) { return NULL; } ret = jparser_malloc((value_len + 1) * sizeof(char)); if (NULL == ret) { return NULL; } HAL_Snprintf(ret, value_len + 1, "%s", value); return ret; } #if WITH_JSON_KEYS_OF static list_head_t *_LITE_json_keys_of(char *src, int src_len, char *prefix, ...) { static LIST_HEAD(keylist); char *module_name = NULL; char *iter_pre = NULL; char *pos = 0, *key = 0, *val = 0; int klen = 0, vlen = 0, vtype = 0; int magic = 0; unsigned int mlen = 0; #if WITH_MEM_STATS_PER_MODULE va_list ap; va_start(ap, prefix); magic = va_arg(ap, int); if (MEM_MAGIC == magic) { module_name = va_arg(ap, char *); } va_end(ap); #endif if (!strcmp("", prefix)) { INIT_LIST_HEAD(&keylist); } json_object_for_each_kv(src, src_len, pos, key, klen, val, vlen, vtype) { if (key && klen && val && vlen) { json_key_t *entry = NULL; entry = jparser_malloc(sizeof(json_key_t), magic, module_name); if (NULL == entry) { utils_err("jparser_malloc failed!"); return NULL; } memset(entry, 0, sizeof(json_key_t)); mlen = strlen(prefix) + klen + 1; if (module_name) { entry->key = LITE_format_nstring( mlen, "%s%.*s", magic, module_name, prefix, klen, key); } else { entry->key = LITE_format_nstring(mlen, "%s%.*s", prefix, klen, key); } if (NULL == entry->key) { jparser_free(entry); return NULL; } list_add_tail(&entry->list, &keylist); if (JOBJECT == vtype) { mlen = strlen(prefix) + klen + 2; if (module_name) { iter_pre = LITE_format_nstring( mlen, "%s%.*s.", magic, module_name, prefix, klen, key); } else { iter_pre = LITE_format_nstring(mlen, "%s%.*s.", prefix, klen, key); } if (NULL == iter_pre) { return NULL; } _LITE_json_keys_of(val, vlen, iter_pre, magic, module_name); jparser_free(iter_pre); } } } if (!strcmp("", prefix)) { json_key_t *entry = NULL; entry = jparser_malloc(sizeof(json_key_t), magic, module_name); if (NULL == entry) { utils_err("jparser_malloc failed!"); return NULL; } memset(entry, 0, sizeof(json_key_t)); list_add_tail(&entry->list, &keylist); return &keylist; } return NULL; } list_head_t *LITE_json_keys_of(char *src, char *prefix, ...) { char *module_name = NULL; int magic = 0; if (!src || !prefix) { return NULL; } #if WITH_MEM_STATS_PER_MODULE va_list ap; va_start(ap, prefix); magic = va_arg(ap, int); if (MEM_MAGIC == magic) { module_name = va_arg(ap, char *); } va_end(ap); #endif return _LITE_json_keys_of(src, strlen(src), prefix, magic, module_name); } #if WITH_JSON_TOKEN_EXT static list_head_t *_LITE_json_keys_of_ext(int type, char *src, int src_len, char *prefix, ...) { static LIST_HEAD(keylist); char *module_name = NULL; char *iter_pre = NULL; char *pos = 0, *key = 0, *val = 0; int klen = 0, vlen = 0, vtype = 0; int magic = 0; unsigned int count = 1; unsigned int mlen = 0; if (src == NULL || prefix == NULL) { return NULL; } #if WITH_MEM_STATS_PER_MODULE va_list ap; va_start(ap, prefix); magic = va_arg(ap, int); if (MEM_MAGIC == magic) { module_name = va_arg(ap, char *); } va_end(ap); #endif if (!strcmp("", prefix)) { INIT_LIST_HEAD(&keylist); } if (JOBJECT == type) { json_object_for_each_kv(src, src_len, pos, key, klen, val, vlen, vtype) { if (key && klen && val && vlen) { json_key_t *entry = NULL; entry = jparser_malloc(sizeof(json_key_t), magic, module_name); if (NULL == entry) { utils_err("jparser_malloc failed!"); return NULL; } memset(entry, 0, sizeof(json_key_t)); mlen = strlen(prefix) + klen + 1; if (module_name) { entry->key = LITE_format_nstring( mlen, "%s%.*s", magic, module_name, prefix, klen, key); } else { entry->key = LITE_format_nstring(mlen, "%s%.*s", prefix, klen, key); } if (NULL == entry->key) { jparser_free(entry); return NULL; } list_add_tail(&entry->list, &keylist); if (JOBJECT == vtype) { mlen = strlen(prefix) + klen + 2; if (module_name) { iter_pre = LITE_format_nstring(mlen, "%s%.*s.", magic, module_name, prefix, klen, key); } else { iter_pre = LITE_format_nstring(mlen, "%s%.*s.", prefix, klen, key); } if (NULL == iter_pre) { return NULL; } _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); jparser_free(iter_pre); } else if (JARRAY == vtype) { mlen = strlen(prefix) + klen + 1; if (module_name) { iter_pre = LITE_format_nstring(mlen, "%s%.*s", magic, module_name, prefix, klen, key); } else { iter_pre = LITE_format_nstring(mlen, "%s%.*s", prefix, klen, key); } if (NULL == iter_pre) { return NULL; } _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); jparser_free(iter_pre); } } } } else if (JARRAY == type) { json_array_for_each_entry(src, src_len, pos, val, vlen, vtype) { if (val && vlen) { json_key_t *entry = NULL; unsigned int tmp = 0; unsigned int arridxlen = 0; entry = jparser_malloc(sizeof(json_key_t), magic, module_name); if (NULL == entry) { utils_err("jparser_malloc failed!"); return NULL; } memset(entry, 0, sizeof(json_key_t)); tmp = count; do { tmp /= 10; ++arridxlen; } while (tmp); mlen = strlen("%s[%d]") + strlen(prefix) + arridxlen; if (module_name) { entry->key = LITE_format_nstring( mlen, "%s[%d]", magic, module_name, prefix, count); } else { entry->key = LITE_format_nstring(mlen, "%s[%d]", prefix, count); } if (NULL == entry->key) { jparser_free(entry); return NULL; } list_add_tail(&entry->list, &keylist); if (JOBJECT == vtype) { mlen = strlen("%s[%d].") + strlen(prefix) + arridxlen; if (module_name) { iter_pre = LITE_format_nstring( mlen, "%s[%d].", magic, module_name, prefix, count); } else { iter_pre = LITE_format_nstring(mlen, "%s[%d].", prefix, count); } if (NULL == iter_pre) { return NULL; } _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); jparser_free(iter_pre); } else if (JARRAY == vtype) { mlen = strlen("%s[%d]") + strlen(prefix) + arridxlen; if (module_name) { iter_pre = LITE_format_nstring( mlen, "%s[%d]", magic, module_name, prefix, count); } else { iter_pre = LITE_format_nstring(mlen, "%s[%d]", prefix, count); } if (NULL == iter_pre) { return NULL; } _LITE_json_keys_of_ext(vtype, val, vlen, iter_pre, magic, module_name); jparser_free(iter_pre); } ++count; } } } if (!strcmp("", prefix)) { json_key_t *entry = NULL; entry = jparser_malloc(sizeof(json_key_t), magic, module_name); if (NULL == entry) { utils_err("jparser_malloc failed!"); return NULL; } memset(entry, 0, sizeof(json_key_t)); list_add_tail(&entry->list, &keylist); return &keylist; } return NULL; } int contain_arr(const char *src, int src_len, const char **arr_pre) { int i = 0; int ret = -1; int deep = 0; const char *pre = NULL; if (NULL == src || NULL == arr_pre || src_len <= 0) { return -1; } *arr_pre = NULL; for (i = 0; i < src_len; ++i) { switch (src[i]) { case '[': { if (deep != 0) { return ret; } ++deep; if (!pre) { pre = &src[i]; } } break; case ']': { if (deep != 1) { return ret; } --deep; if ('[' == src[i - 1]) { return ret; } } break; default: { if ((pre != NULL) && (0 == deep)) { return ret; } } break; } } if ((NULL != pre) && (pre < src + src_len) && (pre >= src)) { *arr_pre = pre; ret = 0; } return ret; } static char *_json_value_by_arrname(char *src, int src_len, const char *key, int key_len, int *val_len) { char *pos = src; char *entry = NULL; const char *p = NULL; const char *arr_pre = key; const char *arr_suf = NULL; int vtype; int loop; int loop_tmp = 0; do { loop = 0; arr_pre = strchr(arr_pre, '['); if (arr_pre && (arr_pre < key + key_len)) { arr_suf = strchr(arr_pre, ']'); } if (arr_pre && arr_suf && (arr_suf < key + key_len)) { loop_tmp = 0; for (p = arr_pre + 1; p < arr_suf; ++p) { if (*p > '9' || *p < '0') { return NULL; } loop_tmp *= 10; loop_tmp += *p - '0'; } pos = json_get_object(JARRAY, pos, src + src_len); if (pos != 0 && *pos != 0) { if (*pos == '[' && *(pos + 1) == ']') { return NULL; } } json_array_for_each_entry(src, src_len, pos, entry, *val_len, vtype) { if (entry && *val_len) { if (++loop >= loop_tmp) { break; } } } if (loop != loop_tmp) { return NULL; } src = entry; arr_pre = arr_suf + 1; } } while (arr_pre && arr_suf && (arr_pre < key + key_len)); return entry; } void LITE_json_keys_release(list_head_t *keylist) { json_key_t *pos, *tmp; if (NULL == keylist) { return; } list_for_each_entry_safe(pos, tmp, keylist, list, json_key_t) { if (pos->key) { jparser_free(pos->key); } list_del(&pos->list); jparser_free(pos); } } list_head_t *LITE_json_keys_of_ext(char *src, char *prefix, ...) { char *module_name = NULL; int magic = 0; #if WITH_MEM_STATS_PER_MODULE va_list ap; va_start(ap, prefix); magic = va_arg(ap, int); if (MEM_MAGIC == magic) { module_name = va_arg(ap, char *); } va_end(ap); #endif if (!src || !prefix) { return NULL; } return _LITE_json_keys_of_ext(JOBJECT, src, strlen(src), prefix, magic, module_name); } static char *_LITE_json_value_of_ext(char *key, char *src, int src_len, int *val_len) { char *value = NULL; char *delim = NULL; char *key_iter; char *key_next; char *src_iter; const char *arr_pre = NULL; int value_len; int key_len; int obj_key_len = 0; int key_type; int src_iter_len; src_iter = src; src_iter_len = src_len; key_iter = key; value_len = src_iter_len; do { delim = strchr(key_iter, '.'); if (delim != NULL) { key_len = delim - key_iter; key_type = JOBJECT; key_next = key_iter; if (0 == contain_arr(key_next, key_len, &arr_pre)) { key_type = JARRAY; obj_key_len = arr_pre - key_iter; if (obj_key_len) { value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, obj_key_len, &value_len, 0); } else { value = src_iter; } } else { value = json_get_value_by_name_len( src_iter, src_iter_len, key_next, key_len, &value_len, 0); } if (NULL == value) { return NULL; } if (key_type == JARRAY) { value = _json_value_by_arrname( value, value_len, arr_pre, key_len - obj_key_len, &value_len); if (value == NULL) { return NULL; } } src_iter = value; src_iter_len = value_len; key_iter = delim + 1; } } while (delim); key_len = strlen(key_iter); key_next = key_iter; key_type = JOBJECT; if (0 == contain_arr(key_next, key_len, &arr_pre)) { key_type = JARRAY; obj_key_len = arr_pre - key_iter; if (obj_key_len) { value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, obj_key_len, &value_len, 0); } else { value = src_iter; } } else { value = json_get_value_by_name_len(src_iter, src_iter_len, key_next, key_len, &value_len, 0); } if (NULL == value) { return NULL; } if (key_type == JARRAY) { value = _json_value_by_arrname(value, value_len, arr_pre, key_len - obj_key_len, &value_len); if (value == NULL) { return NULL; } } *val_len = value_len; return value; } #endif /* #if WITH_JSON_TOKEN_EXT */ #endif /* #if WITH_JSON_KEYS_OF */ #endif