Example #1
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) {
	jsmntok_t *token;

	int start = parser->pos;

	parser->pos++;

	/* Skip starting quote */
	for (; js[parser->pos] != '\0'; parser->pos++) {
		char c = js[parser->pos];

		/* Quote: end of string */
		if (c == '\"') {
			token = jsmn_alloc_token(parser, tokens, num_tokens);
			if (token == NULL) {
				parser->pos = start;
				return JSMN_ERROR_NOMEM;
			}
			jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
			token->parent = parser->toksuper;
#endif
			return JSMN_SUCCESS;
		}

		/* Backslash: Quoted symbol expected */
		if (c == '\\') {
			parser->pos++;
			switch (js[parser->pos]) {
				/* Allowed escaped symbols */
				case '\"': case '/' : case '\\' : case 'b' :
				case 'f' : case 'r' : case 'n'  : case 't' :
					break;
				/* Allows escaped symbol \uXXXX */
				case 'u':
					parser->pos++;
					int i = 0;
					for(; i < 4 && 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 */
									(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
							parser->pos = start;
							return JSMN_ERROR_INVAL;
						}
						parser->pos++;
					}
					parser->pos--;
					break;
				/* Unexpected symbol */
				default:
					parser->pos = start;
					return JSMN_ERROR_INVAL;
			}
		}
	}
	parser->pos = start;
	return JSMN_ERROR_PART;
}
Example #2
0
/**
 * 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) 
{
   jsmntok_t *token;
   int start;
   
   start = parser->pos;
   
   for (; js[parser->pos] != '\0'; parser->pos++) 
   {
      switch (js[parser->pos]) 
      {
      case ':':
      case '\t' : case '\r' : case '\n' : case ' ' :
      case ','  : case ']'  : case '}' :
         goto found;
      }
      if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
         parser->pos = start;
         return JSMN_ERROR_INVAL;
      }
   }

 found:
   token = jsmn_alloc_token(parser, tokens, num_tokens);
   if (token == NULL) 
   {
      parser->pos = start;
      return JSMN_ERROR_NOMEM;
   }
   jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
   parser->pos--;
   return JSMN_SUCCESS;
}
Example #3
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) 
{
   jsmntok_t *token;

   int start = parser->pos;

   parser->pos++;

   /* Skip starting quote */
   for (; js[parser->pos] != '\0'; parser->pos++) 
   {
      char c = js[parser->pos];

      /* Quote: end of string */
      if (c == '\"') 
      {
         token = jsmn_alloc_token(parser, tokens, num_tokens);
         if (token == NULL) 
         {
            parser->pos = start;
            return JSMN_ERROR_NOMEM;
         }
         if(js[parser->pos + 1] == ':')
         {
            jsmn_fill_token(token, JSMN_NAME, start+1, parser->pos);
         }
         else
         {
            jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
         }
         return JSMN_SUCCESS;
      }

      /* Backslash: Quoted symbol expected */
      if (c == '\\') 
      {
         parser->pos++;
         switch (js[parser->pos]) 
         {
            /* Allowed escaped symbols */
         case '\"': case '/' : case '\\' : case 'b' :
         case 'f' : case 'r' : case 'n'  : case 't' :
            break;
            /* Allows escaped symbol \uXXXX */
         case 'u':
            /* TODO */
            break;
            /* Unexpected symbol */
         default:
            parser->pos = start;
            return JSMN_ERROR_INVAL;
         }
      }
   }
   parser->pos = start;
   return JSMN_ERROR_PART;
}
Example #4
0
/**
 * Fills next available token with JSON primitive.
 */
static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
                                      size_t len, jsmntok_t *tokens, size_t num_tokens) {
    jsmntok_t *token;
    int start;

    start = 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 "]" */
        case ':':
#endif
        case '\t' :
        case '\r' :
        case '\n' :
        case ' ' :
        case ','  :
        case ']'  :
        case '}' :
            goto found;
        }
        if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
            parser->pos = start;
            return JSMN_ERROR_INVAL;
        }
    }
#ifdef JSMN_STRICT
    /* In strict mode primitive must be followed by a comma/object/array */
    parser->pos = start;
    return JSMN_ERROR_PART;
#endif

found:
    if (tokens == NULL) {
        parser->pos--;
        return 0;
    }
    token = jsmn_alloc_token(parser, tokens, num_tokens);
    if (token == NULL) {
        parser->pos = start;
        return JSMN_ERROR_NOMEM;
    }
    jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
#ifdef JSMN_PARENT_LINKS
    token->parent = parser->toksuper;
#endif
    parser->pos--;
    return 0;
}
Example #5
0
/**
 * Filsl next token with JSON string.
 */
static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
		jsmntok_t *tokens, int num_tokens) {
	jsmntok_t *token;

	int start = parser->pos;

	parser->pos++;

	/* Skip starting quote */
	for (; js[parser->pos] != '\0'; parser->pos++) {
		char c = js[parser->pos];

		/* Quote: end of string */
		if (c == '\"') {
			token = jsmn_alloc_token(parser, tokens, num_tokens);
			if (token == NULL) {
				parser->pos = start;
				return JSMN_ERROR_NOMEM;
			}
			jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
			token->parent = parser->toksuper;
#endif
			return JSMN_SUCCESS;
		}

		/* Backslash: Quoted symbol expected */
		if (c == '\\') {
			parser->pos++;
			switch (js[parser->pos]) {
				/* Allowed escaped symbols */
				case '\"': case '/' : case '\\' : case 'b' :
				case 'f' : case 'r' : case 'n'  : case 't' :
					break;
				/* Allows escaped symbol \uXXXX */
				case 'u':
					// \u not supported
					break;
				/* Unexpected symbol */
				default:
					parser->pos = start;
					return JSMN_ERROR_INVAL;
			}
		}
	}
	parser->pos = start;
	return JSMN_ERROR_PART;
}
Example #6
0
/**
 * 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;
}
Example #7
0
/**
 * 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;
}
Example #8
0
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;
}
Example #9
0
static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
		jsmntok_t *tokens, size_t num_tokens)
#endif

{

	jsmntok_t *token;

	int start = parser->pos;		//记录头位置

	parser->pos++;	//越过"

	/* Skip starting quote */
#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 = js[parser->pos];

		/* Quote: end of string */
		if (c == '\"') {		//定位到尾部
			token = jsmn_alloc_token(parser, tokens, num_tokens);
			if (token == NULL) {
				parser->pos = start;
				return JSMN_ERROR_NOMEM;
			}

			jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
			token->parent = parser->toksuper;
#endif
			return JSMN_SUCCESS;
		}

		/* Backslash: Quoted symbol expected */
		if (c == '\\') {
			parser->pos++;							//简单越过
			switch (js[parser->pos]) {
				/* Allowed escaped symbols */
				case '\"': case '/' : case '\\' : case 'b' :
				case 'f' : case 'r' : case 'n'  : case 't' :
					break;

				/* Allows escaped symbol \uXXXX */
				case 'u':
					/* TODO */
					break;

				/* Unexpected symbol */
				default:
					parser->pos = start;
					return JSMN_ERROR_INVAL;
			}
		}


	}
	parser->pos = start;
	return JSMN_ERROR_PART;
}
Example #10
0
/**
 * 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;
}
Example #11
0
/**
 * 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;
}
Example #12
0
/**
 * Fills next available token with JSON primitive.
 */
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
		size_t len, jsmntok_t *tokens, size_t num_tokens) {
	jsmntok_t *token;
	int start;

	start = parser->pos;

	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
		switch (js[parser->pos]) {
			case '\t' : case '\r' : case '\n' : case ' ' :
			case ','  : case ']'  : case '}' :
				goto found;
		}
		if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
			parser->pos = start;
			return JSMN_ERROR_INVAL;
		}
	}
	if ( (parser->pos < len) && (js[parser->pos] != '\0') ) {
		/* In strict mode primitive must be followed by a comma/object/array or end-of-string */
		parser->pos = start;
		return JSMN_ERROR_PART;
	}

found:
	token = jsmn_alloc_token(parser, tokens, num_tokens);
	if (token == NULL) {
		parser->pos = start;
		return JSMN_ERROR_NOMEM;
	}
	jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
	token->parent = parser->toksuper;

	/* parse/validate primitives according */
	do {
		if (js[start] == 't') {
			if ( (token->end - start == 4) && (js[start+1] == 'r') && (js[start+2] == 'u') && (js[start+3] == 'e') ) {
				break;
			}
		} else if (js[start] == 'f') {
			if ( (token->end - start == 5) && (js[start+1] == 'a') && (js[start+2] == 'l') && (js[start+3] == 's') && (js[start+4] == 'e') ) {
				break;
			}
		} else if (js[start] == 'n') {
			if ( (token->end - start == 4) && (js[start+1] == 'u') && (js[start+2] == 'l') && (js[start+3] == 'l') ) {
				break;
			}
		} else {
			if (jsmn_parse_primitive_number(js, token) == 0) {
				break;
			}
		}

		/* primitive validation failed */
		parser->pos = token->start;
		return JSMN_ERROR_PRIMITIVE_INVAL;
	} while (0);

	parser->pos--;
	return 0;
}
Example #13
0
/**
 * 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;
}