diff options
Diffstat (limited to 'libjsmn/jsmn.c')
-rw-r--r-- | libjsmn/jsmn.c | 103 |
1 files changed, 73 insertions, 30 deletions
diff --git a/libjsmn/jsmn.c b/libjsmn/jsmn.c index aa8b12b8020d..2e88fe140d49 100644 --- a/libjsmn/jsmn.c +++ b/libjsmn/jsmn.c @@ -1,15 +1,14 @@ #include <stdlib.h> -#include <string.h> #include "jsmn.h" /** * Allocates a fresh unused token from the token pull. */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *tok; - if ((size_t)parser->toknext >= num_tokens) { + if (parser->toknext >= num_tokens) { return NULL; } tok = &tokens[parser->toknext++]; @@ -24,7 +23,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, /** * Fills token type and boundaries. */ -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) { token->type = type; token->start = start; @@ -36,13 +35,13 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, * Fills next available token with JSON primitive. */ static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, - jsmntok_t *tokens, size_t num_tokens) { + size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; int start; start = parser->pos; - for (; js[parser->pos] != '\0'; parser->pos++) { + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { switch (js[parser->pos]) { #ifndef JSMN_STRICT /* In strict mode primitive must be followed by "," or "}" or "]" */ @@ -64,6 +63,10 @@ static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, #endif found: + if (tokens == NULL) { + parser->pos--; + return 0; + } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { parser->pos = start; @@ -74,14 +77,14 @@ found: token->parent = parser->toksuper; #endif parser->pos--; - return JSMN_SUCCESS; + return 0; } /** * Filsl next token with JSON string. */ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, - jsmntok_t *tokens, size_t num_tokens) { + size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; int start = parser->pos; @@ -89,11 +92,14 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, parser->pos++; /* Skip starting quote */ - for (; js[parser->pos] != '\0'; parser->pos++) { + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { char c = js[parser->pos]; /* Quote: end of string */ if (c == '\"') { + if (tokens == NULL) { + return 0; + } token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) { parser->pos = start; @@ -103,13 +109,12 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, #ifdef JSMN_PARENT_LINKS token->parent = parser->toksuper; #endif - return JSMN_SUCCESS; + return 0; } /* Backslash: Quoted symbol expected */ - if (c == '\\') { - int i = 0; - + if (c == '\\' && parser->pos + 1 < len) { + int i; parser->pos++; switch (js[parser->pos]) { /* Allowed escaped symbols */ @@ -119,7 +124,7 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, /* Allows escaped symbol \uXXXX */ case 'u': parser->pos++; - for(; i < 4 && js[parser->pos] != '\0'; i++) { + for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { /* If it isn't a hex character we have an error */ if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ @@ -145,19 +150,24 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, /** * 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 jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { jsmnerr_t r; int i; jsmntok_t *token; + int count = 0; - for (; js[parser->pos] != '\0'; parser->pos++) { + 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; @@ -172,6 +182,8 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, 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) { @@ -216,25 +228,56 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, #endif break; case '\"': - r = jsmn_parse_string(parser, js, tokens, num_tokens); + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); if (r < 0) return r; - if (parser->toksuper != -1) + count++; + if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++; break; - case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': + 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, tokens, num_tokens); + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); if (r < 0) return r; - if (parser->toksuper != -1) + count++; + if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++; break; @@ -243,22 +286,22 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens, 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; + if (tokens != NULL) { + 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; + return count; } /** - * Creates a new parser based over a given buffer with an array of tokens + * Creates a new parser based over a given buffer with an array of tokens * available. */ void jsmn_init(jsmn_parser *parser) { |