|
|
| version 1.1.2.2, 2017/11/24 15:52:57 | version 1.1.2.5, 2017/11/28 02:00:45 |
|---|---|
| Line 105 json_free(json_t * __restrict json) | Line 105 json_free(json_t * __restrict json) |
| } | } |
| } | } |
| static jtok_t * | |
| json_gettoken(json_t * __restrict json, jtok_t * __restrict jtoks, u_int toksnum) | |
| { | |
| jtok_t *tok; | |
| assert(json || !(!jtoks && toksnum)); | |
| if (json->h_next >= toksnum) { | |
| elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]); | |
| return NULL; | |
| } else | |
| tok = &jtoks[json->h_next++]; | |
| tok->tok_start = tok->tok_end = tok->tok_parent = -1; | |
| tok->tok_size = 0; | |
| return tok; | |
| } | |
| inline void | |
| json_filltoken(jtok_t * __restrict tok, jtype_t type, long start, long end, long parent) | |
| { | |
| assert(tok); | |
| tok->tok_type = type; | |
| tok->tok_start = start; | |
| tok->tok_end = end; | |
| tok->tok_parent = parent; | |
| tok->tok_size = 0; | |
| } | |
| static int | |
| json_parse_string(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum) | |
| { | |
| jtok_t *tok; | |
| u_long pos; | |
| char ch; | |
| register int i; | |
| assert(json || jstr || !(!jtoks && toksnum)); | |
| for (pos = json->h_pos++; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) { | |
| ch = jstr[json->h_pos]; | |
| if (ch == '\"') { | |
| if (!jtoks) | |
| return 0; | |
| if (!(tok = json_gettoken(json, jtoks, toksnum))) { | |
| json->h_pos = pos; | |
| return -1; | |
| } else | |
| json_filltoken(tok, J_STRING, pos + 1, json->h_pos, json->h_parent); | |
| return 0; | |
| } | |
| if (ch == '\\' && json->h_pos + 1 < jlen) { | |
| switch (jstr[++json->h_pos]) { | |
| case '\"': | |
| case '/': | |
| case '\\': | |
| case 'b': | |
| case 'f': | |
| case 'r': | |
| case 'n': | |
| case 't': | |
| /* Allowed escaped symbols */ | |
| break; | |
| case 'u': | |
| /* Allows escaped symbol \uXXXX */ | |
| json->h_pos++; | |
| for (i = 0; i < 4 && json->h_pos < jlen && jstr[json->h_pos]; i++, json->h_pos++) { | |
| /* If it isn't a hex character we have an error */ | |
| if (!((jstr[json->h_pos] >= 48 && jstr[json->h_pos] <= 57) || /* 0-9 */ | |
| (jstr[json->h_pos] >= 65 && jstr[json->h_pos] <= 70) || /* A-F */ | |
| (jstr[json->h_pos] >= 97 && jstr[json->h_pos] <= 102))) { /* a-f */ | |
| json->h_pos = pos; | |
| elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); | |
| return -1; | |
| } | |
| } | |
| json->h_pos--; | |
| break; | |
| default: | |
| /* Unexpected symbol */ | |
| json->h_pos = pos; | |
| elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); | |
| return -1; | |
| } | |
| } | |
| } | |
| json->h_pos = pos; | |
| elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]); | |
| return -1; | |
| } | |
| static int | |
| json_parse_value(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum) | |
| { | |
| jtok_t *tok; | |
| u_long pos; | |
| assert(json || jstr || !(!jtoks && toksnum)); | |
| for (pos = json->h_pos; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) { | |
| switch (jstr[json->h_pos]) { | |
| case ':': | |
| if (json->h_strict) | |
| goto found; | |
| break; | |
| case '\t': | |
| case '\r': | |
| case '\n': | |
| case ' ': | |
| case ',': | |
| case ']': | |
| case '}': | |
| goto found; | |
| } | |
| if (jstr[json->h_pos] < 32 || jstr[json->h_pos] > 127) { | |
| json->h_pos = pos; | |
| elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); | |
| return -1; | |
| } | |
| } | |
| if (json->h_strict) { | |
| json->h_pos = pos; | |
| elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]); | |
| return -1; | |
| } | |
| found: | |
| if (jtoks) { | |
| if (!(tok = json_gettoken(json, jtoks, toksnum))) { | |
| json->h_pos = pos; | |
| return -1; | |
| } else | |
| json_filltoken(tok, J_VALUE, pos, json->h_pos, json->h_parent); | |
| } | |
| json->h_pos--; | |
| return 0; | |
| } | |
| /* | /* |
| * json_parse() - Parse JSON string | * json_parse() - Parse JSON string |
| * | * |
| Line 138 json_parse(json_t * __restrict json, const char *jstr, | Line 281 json_parse(json_t * __restrict json, const char *jstr, |
| break; | break; |
| tok = json_gettoken(json, jtoks, toksnum); | tok = json_gettoken(json, jtoks, toksnum); |
| if (!tok) { | if (!tok) |
| elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]); | |
| return (u_int) -1; | return (u_int) -1; |
| } | |
| if (json->h_parent != -1) { | if (json->h_parent != -1) { |
| jtoks[json->h_parent].tok_size++; | jtoks[json->h_parent].tok_size++; |
| tok->tok_parent = json->h_parent; | tok->tok_parent = json->h_parent; |
| Line 220 json_parse(json_t * __restrict json, const char *jstr, | Line 361 json_parse(json_t * __restrict json, const char *jstr, |
| case 't': | case 't': |
| case 'f': | case 'f': |
| case 'n': | case 'n': |
| if (!json->h_strict) | if (json->h_strict) { |
| break; | if (jtoks && json->h_parent != -1) { |
| /* they must not be keys of the object */ | |
| if (jtoks[json->h_parent].tok_type == J_OBJECT || | |
| (jtoks[json->h_parent].tok_type == J_STRING && | |
| jtoks[json->h_parent].tok_size)) { | |
| elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); | |
| return (u_int) -1; | |
| } | |
| } | |
| if (jtoks && json->h_parent != -1) { | if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1) |
| /* they must not be keys of the object */ | |
| if (jtoks[json->h_parent].tok_type == J_OBJECT || | |
| (jtoks[json->h_parent].tok_type == J_STRING && | |
| jtoks[json->h_parent].tok_size)) { | |
| elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); | |
| return (u_int) -1; | return (u_int) -1; |
| } | cx++; |
| if (jtoks && json->h_parent != -1) | |
| jtoks[json->h_parent].tok_size++; | |
| break; | |
| } | } |
| if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1) | |
| return (u_int) -1; | |
| cx++; | |
| if (jtoks && json->h_parent != -1) | |
| jtoks[json->h_parent].tok_size++; | |
| break; | |
| default: | default: |
| if (json->h_strict) { | if (json->h_strict) { |
| elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); | elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); |
| Line 265 json_parse(json_t * __restrict json, const char *jstr, | Line 405 json_parse(json_t * __restrict json, const char *jstr, |
| } | } |
| return cx; | return cx; |
| } | |
| /* | |
| * json_token2val() - Return token to AIT variable | |
| * | |
| * @jstr = JSON string | |
| * @tok = Token for convert | |
| * @return =NULL error or !=NULL allocated variable, after use should be ait_freeVar() | |
| */ | |
| ait_val_t * | |
| json_token2val(const char *jstr, jtok_t * __restrict tok) | |
| { | |
| ait_val_t *v = NULL; | |
| if (!jstr || !tok) | |
| return NULL; | |
| v = ait_allocVar(); | |
| if (!v) | |
| return NULL; | |
| AIT_SET_STRSIZ(v, tok->tok_end - tok->tok_start); | |
| strncpy(AIT_GET_STR(v), jstr + tok->tok_start, AIT_LEN(v) - 1); | |
| return v; | |
| } | |
| /* | |
| * json_token2str() - Return token to string | |
| * | |
| * @jstr = JSON string | |
| * @tok = Token for convert | |
| * @return =NULL error or !=NULL allocated str, after use should be e_free() | |
| */ | |
| char * | |
| json_token2str(const char *jstr, jtok_t * __restrict tok) | |
| { | |
| char *str = NULL; | |
| size_t len; | |
| if (!jstr || !tok) | |
| return NULL; | |
| len = tok->tok_end - tok->tok_start; | |
| str = e_malloc(len + 1); | |
| if (!str) | |
| return NULL; | |
| else { | |
| strncpy(str, jstr + tok->tok_start, len); | |
| str[len] = 0; | |
| } | |
| return str; | |
| } | |
| /* | |
| * json_token2num() - Return token to numeric | |
| * | |
| * @jstr = JSON string | |
| * @tok = Token for convert | |
| * @return number | |
| */ | |
| long | |
| json_token2num(const char *jstr, jtok_t * __restrict tok) | |
| { | |
| long ret = 0; | |
| char *str; | |
| str = json_token2str(jstr, tok); | |
| if (!str) | |
| return 0; | |
| ret = strtol(str, NULL, 0); | |
| e_free(str); | |
| return ret; | |
| } | |
| /* | |
| * json_findbykey() - Find data by key | |
| * | |
| * @jstr = JSON string | |
| * @key = Search key | |
| * @toks = Parsed tokens | |
| * @toksnum = Number of parsed tokens | |
| * return: =NULL error or !=NULL data token found | |
| */ | |
| jtok_t * | |
| json_findbykey(const char *jstr, const char *key, jtok_t * __restrict toks, int toksnum) | |
| { | |
| jtok_t *tok = NULL; | |
| register int i; | |
| int klen; | |
| if (!jstr || !key || !toks) | |
| return NULL; | |
| else | |
| klen = strlen(key); | |
| for (i = 1; i < toksnum; i++) { | |
| if (toks[i].tok_type == J_STRING && | |
| klen == toks[i].tok_end - toks[i].tok_start && | |
| !strncmp(jstr + toks[i].tok_start, key, klen)) { | |
| tok = toks + i + 1; | |
| break; | |
| } | |
| } | |
| return tok; | |
| } | |
| /* | |
| * json_token2array() - Convert token to array | |
| * | |
| * @jstr = JSON string | |
| * @tok = Token for convert | |
| * return: =NULL error or !=NULL allocated array with variables, | |
| * after use should be ait_freeVars() | |
| */ | |
| array_t * | |
| json_token2array(const char *jstr, jtok_t * __restrict tok) | |
| { | |
| array_t *arr = NULL; | |
| register int i; | |
| int siz; | |
| ait_val_t *v; | |
| jtok_t *t; | |
| if (!jstr || !tok) | |
| return NULL; | |
| siz = tok->tok_size; | |
| if (!siz && json_toktype(tok) != J_ARRAY && json_toktype(tok) != J_OBJECT) | |
| siz++; | |
| arr = ait_allocVars(siz); | |
| if (!arr) | |
| return NULL; | |
| if (tok->tok_type == J_STRING || tok->tok_type == J_VALUE) { | |
| v = ait_getVars(&arr, 0); | |
| AIT_SET_STRSIZ(v, json_toklen(tok)); | |
| json_tokstrcpy(AIT_GET_STR(v), jstr, tok); | |
| } else if (tok->tok_type == J_ARRAY) { | |
| for (i = 0; i < tok->tok_size; i++) { | |
| t = &tok[i + 1]; | |
| v = ait_getVars(&arr, i); | |
| AIT_SET_STRSIZ(v, json_toklen(t)); | |
| json_tokstrcpy(AIT_GET_STR(v), jstr, t); | |
| } | |
| } else { | |
| /* todo for object */ | |
| } | |
| return arr; | |
| } | } |