mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										69
									
								
								ArduinoJsonParser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								ArduinoJsonParser.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | /* | ||||||
|  |  * malloc-free JSON parser for Arduino | ||||||
|  |  * Benoit Blanchon 2014 | ||||||
|  |  * MIT License | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef __ARDUINOJSONPARSER_H | ||||||
|  | #define __ARDUINOJSONPARSER_H | ||||||
|  |  | ||||||
|  | #include <Arduino.h> | ||||||
|  | #include "utility/jsmn.h" | ||||||
|  |  | ||||||
|  | template <int N> | ||||||
|  | class ArduinoJsonParser | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  | 	ArduinoJsonParser() | ||||||
|  | 	{ | ||||||
|  | 		jsmn_init(&parser); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	boolean parse(char* jsonString) | ||||||
|  | 	{ | ||||||
|  | 		buffer = jsonString; | ||||||
|  |  | ||||||
|  | 		int tokenCount = sizeof(tokens) / sizeof(tokens[0]); | ||||||
|  |  | ||||||
|  | 		if (JSMN_SUCCESS != jsmn_parse(&parser, jsonString, tokens, tokenCount)) | ||||||
|  | 			return false; | ||||||
|  |  | ||||||
|  | 		// Add null termination to each token | ||||||
|  | 		for (int i = 0; i < tokenCount; i++) | ||||||
|  | 		{ | ||||||
|  | 			buffer[tokens[i].end] = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	char* getValue(char* name) | ||||||
|  | 	{ | ||||||
|  | 		// Scan each keys, every two other token | ||||||
|  | 		// (skip index 0, because it's the whole json object) | ||||||
|  | 		for (int i = 1; i < 2 * N; i += 2) | ||||||
|  | 		{ | ||||||
|  | 			// Early break if we reach the last token | ||||||
|  | 			if (i >= parser.toknext) break; | ||||||
|  |  | ||||||
|  | 			// Get key token string | ||||||
|  | 			char* key = buffer + tokens[i].start; | ||||||
|  |  | ||||||
|  | 			// Compare with desired name, ignoring case | ||||||
|  | 			if (strcasecmp(name, key) == 0) | ||||||
|  | 			{ | ||||||
|  | 				return buffer + tokens[i + 1].start; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |  | ||||||
|  | 	char* buffer; | ||||||
|  | 	jsmn_parser parser; | ||||||
|  | 	jsmntok_t tokens[N * 2 + 1]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
							
								
								
									
										255
									
								
								utility/jsmn.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								utility/jsmn.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | |||||||
|  | #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; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										67
									
								
								utility/jsmn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								utility/jsmn.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | #ifndef __JSMN_H_ | ||||||
|  | #define __JSMN_H_ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * JSON type identifier. Basic types are: | ||||||
|  |  * 	o Object | ||||||
|  |  * 	o Array | ||||||
|  |  * 	o String | ||||||
|  |  * 	o Other primitive: number, boolean (true/false) or null | ||||||
|  |  */ | ||||||
|  | typedef enum { | ||||||
|  | 	JSMN_PRIMITIVE = 0, | ||||||
|  | 	JSMN_OBJECT = 1, | ||||||
|  | 	JSMN_ARRAY = 2, | ||||||
|  | 	JSMN_STRING = 3 | ||||||
|  | } jsmntype_t; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  | 	/* Not enough tokens were provided */ | ||||||
|  | 	JSMN_ERROR_NOMEM = -1, | ||||||
|  | 	/* Invalid character inside JSON string */ | ||||||
|  | 	JSMN_ERROR_INVAL = -2, | ||||||
|  | 	/* The string is not a full JSON packet, more bytes expected */ | ||||||
|  | 	JSMN_ERROR_PART = -3, | ||||||
|  | 	/* Everything was fine */ | ||||||
|  | 	JSMN_SUCCESS = 0 | ||||||
|  | } jsmnerr_t; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * JSON token description. | ||||||
|  |  * @param		type	type (object, array, string etc.) | ||||||
|  |  * @param		start	start position in JSON data string | ||||||
|  |  * @param		end		end position in JSON data string | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  | 	jsmntype_t type; | ||||||
|  | 	int start; | ||||||
|  | 	int end; | ||||||
|  | 	int size; | ||||||
|  | #ifdef JSMN_PARENT_LINKS | ||||||
|  | 	int parent; | ||||||
|  | #endif | ||||||
|  | } jsmntok_t; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * JSON parser. Contains an array of token blocks available. Also stores | ||||||
|  |  * the string being parsed now and current position in that string | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  | 	unsigned int pos; /* offset in the JSON string */ | ||||||
|  | 	int toknext; /* next token to allocate */ | ||||||
|  | 	int toksuper; /* superior token node, e.g parent object or array */ | ||||||
|  | } jsmn_parser; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Create JSON parser over an array of tokens | ||||||
|  |  */ | ||||||
|  | void jsmn_init(jsmn_parser *parser); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Run JSON parser. It parses a JSON data string into and array of tokens, each describing | ||||||
|  |  * a single JSON object. | ||||||
|  |  */ | ||||||
|  | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,  | ||||||
|  | 		jsmntok_t *tokens, unsigned int num_tokens); | ||||||
|  |  | ||||||
|  | #endif /* __JSMN_H_ */ | ||||||
		Reference in New Issue
	
	Block a user