mirror of
				https://github.com/bblanchon/ArduinoJson.git
				synced 2025-11-04 00:21:36 +01:00 
			
		
		
		
	
		
			
	
	
		
			256 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			256 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "jsmn.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Allocates a fresh unused token from the token pull.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, 
							 | 
						||
| 
								 | 
							
										jsmntok_t *tokens, size_t num_tokens) {
							 | 
						||
| 
								 | 
							
									jsmntok_t *tok;
							 | 
						||
| 
								 | 
							
									if (parser->toknext >= num_tokens) {
							 | 
						||
| 
								 | 
							
										return NULL;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									tok = &tokens[parser->toknext++];
							 | 
						||
| 
								 | 
							
									tok->start = tok->end = -1;
							 | 
						||
| 
								 | 
							
									tok->size = 0;
							 | 
						||
| 
								 | 
							
								#ifdef JSMN_PARENT_LINKS
							 | 
						||
| 
								 | 
							
									tok->parent = -1;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
									return tok;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Fills token type and boundaries.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, 
							 | 
						||
| 
								 | 
							
								                            int start, int end) {
							 | 
						||
| 
								 | 
							
									token->type = type;
							 | 
						||
| 
								 | 
							
									token->start = start;
							 | 
						||
| 
								 | 
							
									token->end = end;
							 | 
						||
| 
								 | 
							
									token->size = 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]) {
							 | 
						||
| 
								 | 
							
								#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:
							 | 
						||
| 
								 | 
							
									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 JSMN_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * 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':
							 | 
						||
| 
								 | 
							
													/* TODO */
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
												/* Unexpected symbol */
							 | 
						||
| 
								 | 
							
												default:
							 | 
						||
| 
								 | 
							
													parser->pos = start;
							 | 
						||
| 
								 | 
							
													return JSMN_ERROR_INVAL;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									parser->pos = start;
							 | 
						||
| 
								 | 
							
									return JSMN_ERROR_PART;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * 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
							 | 
						||
| 
								 | 
							
											/* 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 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;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Creates a new parser based over a given  buffer with an array of tokens 
							 | 
						||
| 
								 | 
							
								 * available.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								void jsmn_init(jsmn_parser *parser) {
							 | 
						||
| 
								 | 
							
									parser->pos = 0;
							 | 
						||
| 
								 | 
							
									parser->toknext = 0;
							 | 
						||
| 
								 | 
							
									parser->toksuper = -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |