/** * Parse JSON string and fill tokens. */ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens) { int r; int i; jsmntok_t *token; int count = 0; for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': count++; if (tokens == NULL) { break; } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif } token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->start = parser->pos; parser->toksuper = parser->toknext - 1; break; case '}': case ']': if (tokens == NULL) break; type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS if (parser->toknext < 1) { return JSMN_ERROR_INVAL; } token = &tokens[parser->toknext - 1]; for (;;) { if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } token->end = parser->pos + 1; parser->toksuper = token->parent; break; } if (token->parent == -1) { break; } token = &tokens[token->parent]; } #else for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } parser->toksuper = -1; token->end = parser->pos + 1; break; } } /* Error if unmatched closing bracket */ if (i == -1) return JSMN_ERROR_INVAL; for (; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->toksuper = i; break; } } #endif break; case '\"': r = jsmn_parse_string(parser, js, len, tokens, num_tokens); if (r < 0) return r; count++; if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++; break; case '\t' : case '\r' : case '\n' : case ' ': break; case ':': parser->toksuper = parser->toknext - 1; break; case ',': if (tokens != NULL && tokens[parser->toksuper].type != JSMN_ARRAY && tokens[parser->toksuper].type != JSMN_OBJECT) { #ifdef JSMN_PARENT_LINKS parser->toksuper = tokens[parser->toksuper].parent; #else for (i = parser->toknext - 1; i >= 0; i--) { if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { if (tokens[i].start != -1 && tokens[i].end == -1) { parser->toksuper = i; break; } } } #endif } break; #ifdef JSMN_STRICT /* In strict mode primitives are: numbers and booleans */ case '-': case '0': case '1' : case '2': case '3' : case '4': case '5': case '6': case '7' : case '8': case '9': case 't': case 'f': case 'n' : /* And they must not be keys of the object */ if (tokens != NULL) { jsmntok_t *t = &tokens[parser->toksuper]; if (t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0)) { return JSMN_ERROR_INVAL; } } #else /* In non-strict mode every unquoted value is a primitive */ default: #endif r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); if (r < 0) return r; count++; if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++; break; #ifdef JSMN_STRICT /* Unexpected char in strict mode */ default: return JSMN_ERROR_INVAL; #endif } } for (i = parser->toknext - 1; i >= 0; i--) { /* Unmatched opened object or array */ if (tokens[i].start != -1 && tokens[i].end == -1) { return JSMN_ERROR_PART; } } return count; }
/** * Parse JSON string and fill tokens. */ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, unsigned int num_tokens) { int r; int i; jsmntok_t *token; /* initialize the rest of tokens (they could be reallocated) */ for (i = parser->toknext; i < num_tokens; i++) { jsmn_fill_token(&tokens[i], JSMN_PRIMITIVE, -1, -1); } for (; js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; if (parser->toksuper != -1) tokens[parser->toksuper].size++; token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->start = parser->pos; parser->toksuper = parser->toknext - 1; break; case '}': case ']': type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } parser->toksuper = -1; token->end = parser->pos + 1; break; } } /* Error if unmatched closing bracket */ if (i == -1) return JSMN_ERROR_INVAL; for (; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->toksuper = i; break; } } break; case '\"': r = jsmn_parse_string(parser, js, tokens, num_tokens); if (r < 0) return jsmnerr_t(r); if (parser->toksuper != -1) tokens[parser->toksuper].size++; break; case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': break; #ifdef JSMN_STRICT /* In strict mode primitives are: numbers and booleans */ case '-': case '0': case '1' : case '2': case '3' : case '4': case '5': case '6': case '7' : case '8': case '9': case 't': case 'f': case 'n' : #else /* In non-strict mode every unquoted value is a primitive */ default: #endif r = jsmn_parse_primitive(parser, js, tokens, num_tokens); if (r < 0) return jsmnerr_t(r); if (parser->toksuper != -1) tokens[parser->toksuper].size++; break; #ifdef JSMN_STRICT /* Unexpected char in strict mode */ default: return JSMN_ERROR_INVAL; #endif } } for (i = parser->toknext - 1; i >= 0; i--) { /* Unmatched opened object or array */ if (tokens[i].start != -1 && tokens[i].end == -1) { return JSMN_ERROR_PART; } } return JSMN_SUCCESS; }
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, unsigned int num_tokens) #endif { jsmnerr_t r; int i; jsmntok_t *token; #ifdef JSMN_OPTIMIZE for (; js[parser->pos] != '\0' && parser->pos < js_len; parser->pos++) #else for (; js[parser->pos] != '\0'; parser->pos++) #endif { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif } token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->start = parser->pos; parser->toksuper = parser->toknext - 1; //上一层 改为 上一个token break; case '}': case ']': type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS if (parser->toknext < 1) { return JSMN_ERROR_INVAL; } token = &tokens[parser->toknext - 1]; //当前token(尾部的token) for (;;) { if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } token->end = parser->pos + 1; parser->toksuper = token->parent; break; } if (token->parent == -1) { break; } token = &tokens[token->parent]; } #else for (i = parser->toknext - 1; i >= 0; i--) { //回溯 token = &tokens[i]; if (token->start != -1 && token->end == -1) { //找到还没有结尾的token 就是 { [ 的tk if (token->type != type) { return JSMN_ERROR_INVAL; } parser->toksuper = -1; token->end = parser->pos + 1; //结尾之 break; } } /* Error if unmatched closing bracket */ if (i == -1) return JSMN_ERROR_INVAL; //找到头也没有 for (; i >= 0; i--) { //接着回溯 token = &tokens[i]; if (token->start != -1 && token->end == -1) { //找到再上一级的对象tk parser->toksuper = i; break; } } #endif break; case '\"': #ifdef JSMN_OPTIMIZE r = jsmn_parse_string(parser, js, js_len, tokens, num_tokens); #else r = jsmn_parse_string(parser, js, tokens, num_tokens); #endif if (r < 0) return r; if (parser->toksuper != -1) //如果有上一层 那么为其添加数量 tokens[parser->toksuper].size++; break; case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': //越过空白字符 break; #ifdef JSMN_STRICT /* In strict mode primitives are: numbers and booleans */ case '-': case '0': case '1' : case '2': case '3' : case '4': case '5': case '6': case '7' : case '8': case '9': case 't': case 'f': case 'n' : #else /* In non-strict mode every unquoted value is a primitive */ default: #endif #ifdef JSMN_OPTIMIZE r = jsmn_parse_primitive(parser, js, js_len, tokens, num_tokens); #else r = jsmn_parse_primitive(parser, js, tokens, num_tokens); #endif if (r < 0) return r; if (parser->toksuper != -1) tokens[parser->toksuper].size++; break; #ifdef JSMN_STRICT /* Unexpected char in strict mode */ default: return JSMN_ERROR_INVAL; #endif } } for (i = parser->toknext - 1; i >= 0; i--) { //回溯 /* Unmatched opened object or array */ if (tokens[i].start != -1 && tokens[i].end == -1) { //若是还能找到未圆满的tk return JSMN_ERROR_PART; } } return JSMN_SUCCESS; }
/** * Parse JSON string and fill tokens. */ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, unsigned int num_tokens) { jsmnerr_t r; int i; jsmntok_t *token; for (; js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { return JSMN_ERROR_NOMEM; } if (parser->toksuper != -1) { tokens[parser->toksuper].size++; #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif } token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->start = parser->pos; parser->toksuper = parser->toknext - 1; break; case '}': case ']': type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS if (parser->toknext < 1) { return JSMN_ERROR_INVAL; } token = &tokens[parser->toknext - 1]; for (;;) { if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } token->end = parser->pos + 1; parser->toksuper = token->parent; break; } if (token->parent == -1) { break; } token = &tokens[token->parent]; } #else for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } parser->toksuper = -1; token->end = parser->pos + 1; break; } } /* Error if unmatched closing bracket */ if (i == -1) { return JSMN_ERROR_INVAL; } for (; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->toksuper = i; break; } } #endif break; case '\"': r = jsmn_parse_string(parser, js, tokens, num_tokens); if (r < 0) { return r; } if (parser->toksuper != -1) { tokens[parser->toksuper].size++; } break; case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': break; #ifdef JSMN_STRICT /* Strict mode: Primitives are numbers and booleans */ case '-': case '0': case '1' : case '2': case '3' : case '4': case '5': case '6': case '7' : case '8': case '9': case 't': case 'f': case 'n' : #else /* Non-strict mode: Every unquoted value is a primitive */ default: #endif r = jsmn_parse_primitive(parser, js, tokens, num_tokens); if (r < 0) { return r; } if (parser->toksuper != -1) { tokens[parser->toksuper].size++; } break; #ifdef JSMN_STRICT /* Unexpected char in strict mode */ default: return JSMN_ERROR_INVAL; #endif } } for (i = parser->toknext - 1; i >= 0; i--) { /* Unmatched opened object or array */ if (tokens[i].start != -1 && tokens[i].end == -1) { return JSMN_ERROR_PART; } } return JSMN_SUCCESS; }
/** * Parse JSON string and fill tokens. */ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens) { int r; int i; jsmntok_priv_t *token; int depth = 0; int count = parser->toknext; if (tokens == NULL) { return JSMN_ERROR_NOMEM; } for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': /* check previous token is valid */ if (parser->toknext >= 1) { token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; depth = token->_depth; switch (token->_lasttype) { case _JSMN_SEPARATOR_COMMA: case _JSMN_SEPARATOR_COLON: case JSMN_ARRAY: break; default: return JSMN_ERROR_INVAL; } } /* check parent token is valid */ if (parser->toksuper != -1) { token = (jsmntok_priv_t *)&tokens[parser->toksuper]; if (token->type == JSMN_OBJECT) { return JSMN_ERROR_INVAL; } } count++; token = (jsmntok_priv_t *)jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; token->parent = parser->toksuper; jsmn_percolate_skip_counts(tokens, parser->toksuper); } token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->_lasttype = token->type; token->_depth = depth+1; token->start = parser->pos; parser->toksuper = parser->toknext - 1; break; case '}': case ']': type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); if (parser->toksuper == -1) { return JSMN_ERROR_INVAL; } if (parser->toknext < 1) { return JSMN_ERROR_INVAL; } token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; switch (token->_lasttype) { case JSMN_PRIMITIVE: case JSMN_STRING: case JSMN_OBJECT: case JSMN_ARRAY: case _JSMN_OBJECT_END: case _JSMN_ARRAY_END: break; default: return JSMN_ERROR_INVAL; } for (;;) { if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } token->end = parser->pos + 1; parser->toksuper = token->parent; token->_depth--; break; } if (token->parent == -1) { break; } token = (jsmntok_priv_t *)&tokens[token->parent]; } token->_lasttype = token->type == JSMN_OBJECT ? _JSMN_OBJECT_END : _JSMN_ARRAY_END; break; case '\"': if (parser->toknext >= 1) { token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; depth = token->_depth; switch (token->_lasttype) { case JSMN_OBJECT: case JSMN_ARRAY: case _JSMN_SEPARATOR_COLON: case _JSMN_SEPARATOR_COMMA: break; default: return JSMN_ERROR_INVAL; } } r = jsmn_parse_string(parser, js, len, tokens, num_tokens); if (r < 0) return r; count++; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; jsmn_percolate_skip_counts(tokens, parser->toksuper); token = (jsmntok_priv_t *)&tokens[parser->toksuper]; type = token->_lasttype == JSMN_OBJECT ? _JSMN_STRING_KEY : JSMN_STRING; } else { type = JSMN_STRING; } token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; token->_lasttype = type; token->_depth = depth; break; case '\t' : case '\r' : case '\n' : case ' ': break; case ':': if (parser->toksuper == -1) { return JSMN_ERROR_INVAL; } assert(parser->toknext >= 1); token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; switch (token->_lasttype) { case _JSMN_STRING_KEY: break; default: return JSMN_ERROR_INVAL; } parser->toksuper = parser->toknext - 1; token->_lasttype = _JSMN_SEPARATOR_COLON; break; case ',': if (parser->toksuper == -1) { return JSMN_ERROR_INVAL; } assert(parser->toknext >= 1); token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; switch (token->_lasttype) { case JSMN_PRIMITIVE: case JSMN_STRING: case _JSMN_OBJECT_END: case _JSMN_ARRAY_END: break; default: return JSMN_ERROR_INVAL; } if ( tokens[parser->toksuper].type != JSMN_ARRAY && tokens[parser->toksuper].type != JSMN_OBJECT) { parser->toksuper = tokens[parser->toksuper].parent; } token->_lasttype = _JSMN_SEPARATOR_COMMA; break; /* In strict mode primitives are: numbers and booleans */ case '-': case '0': case '1' : case '2': case '3' : case '4': case '5': case '6': case '7' : case '8': case '9': case 't': case 'f': case 'n' : /* And they must not be keys of the object */ if (parser->toksuper != -1) { token = (jsmntok_priv_t *)&tokens[parser->toksuper]; if (token->type == JSMN_OBJECT || (token->type == JSMN_STRING && token->size != 0)) { return JSMN_ERROR_INVAL; } depth = token->_depth; } if (parser->toknext >= 1) { token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; switch (token->_lasttype) { case JSMN_ARRAY: case _JSMN_SEPARATOR_COLON: case _JSMN_SEPARATOR_COMMA: break; default: return JSMN_ERROR_INVAL; } } r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); if (r < 0) return r; count++; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; jsmn_percolate_skip_counts(tokens, parser->toksuper); } token = (jsmntok_priv_t *)&tokens[parser->toknext - 1]; token->_lasttype = JSMN_PRIMITIVE; token->_depth = depth; break; /* Unexpected char in strict mode */ default: return JSMN_ERROR_INVAL; } } if (tokens[0].type == JSMN_OBJECT || tokens[0].type == JSMN_ARRAY) { /* Unmatched opened object or array */ if (((jsmntok_priv_t *)(&tokens[0]))->_depth != 0) { return JSMN_ERROR_INVAL; } } #ifndef NDEBUG /* sanity checks */ for (i = 0; i < parser->toknext; i++) { assert(tokens[i].start != -1); assert(tokens[i].end != -1); assert(((jsmntok_priv_t *)(&tokens[i]))->_depth != -1); assert(((jsmntok_priv_t *)(&tokens[i]))->_lasttype != JSMN_UNDEFINED); } #endif return count; }
/** * Parse JSON string and fill tokens. */ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, unsigned int num_tokens) { jsmnerr_t r; int i; jsmntok_t *token; for (; js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; c = js[parser->pos]; switch (c) { case '{': case '[': token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; if (parser->toksuper != -1) { tokens[parser->toksuper].size++; } token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); token->start = parser->pos; parser->toksuper = parser->toknext - 1; break; case '}': case ']': type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { if (token->type != type) { return JSMN_ERROR_INVAL; } parser->toksuper = -1; token->end = parser->pos + 1; break; } } /* Error if unmatched closing bracket */ if (i == -1) return JSMN_ERROR_INVAL; for (; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->toksuper = i; break; } } break; case '\"': r = jsmn_parse_string(parser, js, tokens, num_tokens); if (r < 0) return r; if (parser->toksuper != -1) tokens[parser->toksuper].size++; break; case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': break; default: r = jsmn_parse_primitive(parser, js, tokens, num_tokens); if (r < 0) return r; if (parser->toksuper != -1) tokens[parser->toksuper].size++; break; } } for (i = parser->toknext - 1; i >= 0; i--) { /* Unmatched opened object or array */ if (tokens[i].start != -1 && tokens[i].end == -1) { return JSMN_ERROR_PART; } } // Append an "END" token if(parser->toknext < num_tokens) { tokens[parser->toknext].start = tokens[parser->toknext].end = -1; } return JSMN_SUCCESS; }