lnvis

nanovg lightning network visualizer
git clone git://jb55.com/lnvis
Log | Files | Refs | README | LICENSE

jsmn.c (7851B)


      1 #include "jsmn.h"
      2 
      3 /**
      4  * Allocates a fresh unused token from the token pull.
      5  */
      6 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
      7 		jsmntok_t *tokens, size_t num_tokens) {
      8 	jsmntok_t *tok;
      9 	if (parser->toknext >= num_tokens) {
     10 		return NULL;
     11 	}
     12 	tok = &tokens[parser->toknext++];
     13 	tok->start = tok->end = -1;
     14 	tok->size = 0;
     15 #ifdef JSMN_PARENT_LINKS
     16 	tok->parent = -1;
     17 #endif
     18 	return tok;
     19 }
     20 
     21 /**
     22  * Fills token type and boundaries.
     23  */
     24 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
     25                             int start, int end) {
     26 	token->type = type;
     27 	token->start = start;
     28 	token->end = end;
     29 	token->size = 0;
     30 }
     31 
     32 /**
     33  * Fills next available token with JSON primitive.
     34  */
     35 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
     36 		size_t len, jsmntok_t *tokens, size_t num_tokens) {
     37 	jsmntok_t *token;
     38 	int start;
     39 
     40 	start = parser->pos;
     41 
     42 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     43 		switch (js[parser->pos]) {
     44 #ifndef JSMN_STRICT
     45 			/* In strict mode primitive must be followed by "," or "}" or "]" */
     46 			case ':':
     47 #endif
     48 			case '\t' : case '\r' : case '\n' : case ' ' :
     49 			case ','  : case ']'  : case '}' :
     50 				goto found;
     51 		}
     52 		if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
     53 			parser->pos = start;
     54 			return JSMN_ERROR_INVAL;
     55 		}
     56 	}
     57 #ifdef JSMN_STRICT
     58 	/* In strict mode primitive must be followed by a comma/object/array */
     59 	parser->pos = start;
     60 	return JSMN_ERROR_PART;
     61 #endif
     62 
     63 found:
     64 	if (tokens == NULL) {
     65 		parser->pos--;
     66 		return 0;
     67 	}
     68 	token = jsmn_alloc_token(parser, tokens, num_tokens);
     69 	if (token == NULL) {
     70 		parser->pos = start;
     71 		return JSMN_ERROR_NOMEM;
     72 	}
     73 	jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
     74 #ifdef JSMN_PARENT_LINKS
     75 	token->parent = parser->toksuper;
     76 #endif
     77 	parser->pos--;
     78 	return 0;
     79 }
     80 
     81 /**
     82  * Fills next token with JSON string.
     83  */
     84 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
     85 		size_t len, jsmntok_t *tokens, size_t num_tokens) {
     86 	jsmntok_t *token;
     87 
     88 	int start = parser->pos;
     89 
     90 	parser->pos++;
     91 
     92 	/* Skip starting quote */
     93 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     94 		char c = js[parser->pos];
     95 
     96 		/* Quote: end of string */
     97 		if (c == '\"') {
     98 			if (tokens == NULL) {
     99 				return 0;
    100 			}
    101 			token = jsmn_alloc_token(parser, tokens, num_tokens);
    102 			if (token == NULL) {
    103 				parser->pos = start;
    104 				return JSMN_ERROR_NOMEM;
    105 			}
    106 			jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
    107 #ifdef JSMN_PARENT_LINKS
    108 			token->parent = parser->toksuper;
    109 #endif
    110 			return 0;
    111 		}
    112 
    113 		/* Backslash: Quoted symbol expected */
    114 		if (c == '\\' && parser->pos + 1 < len) {
    115 			int i;
    116 			parser->pos++;
    117 			switch (js[parser->pos]) {
    118 				/* Allowed escaped symbols */
    119 				case '\"': case '/' : case '\\' : case 'b' :
    120 				case 'f' : case 'r' : case 'n'  : case 't' :
    121 					break;
    122 				/* Allows escaped symbol \uXXXX */
    123 				case 'u':
    124 					parser->pos++;
    125 					for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
    126 						/* If it isn't a hex character we have an error */
    127 						if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
    128 									(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
    129 									(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
    130 							parser->pos = start;
    131 							return JSMN_ERROR_INVAL;
    132 						}
    133 						parser->pos++;
    134 					}
    135 					parser->pos--;
    136 					break;
    137 				/* Unexpected symbol */
    138 				default:
    139 					parser->pos = start;
    140 					return JSMN_ERROR_INVAL;
    141 			}
    142 		}
    143 	}
    144 	parser->pos = start;
    145 	return JSMN_ERROR_PART;
    146 }
    147 
    148 /**
    149  * Parse JSON string and fill tokens.
    150  */
    151 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
    152 		jsmntok_t *tokens, unsigned int num_tokens) {
    153 	int r;
    154 	int i;
    155 	jsmntok_t *token;
    156 	int count = parser->toknext;
    157 
    158 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
    159 		char c;
    160 		jsmntype_t type;
    161 
    162 		c = js[parser->pos];
    163 		switch (c) {
    164 			case '{': case '[':
    165 				count++;
    166 				if (tokens == NULL) {
    167 					break;
    168 				}
    169 				token = jsmn_alloc_token(parser, tokens, num_tokens);
    170 				if (token == NULL)
    171 					return JSMN_ERROR_NOMEM;
    172 				if (parser->toksuper != -1) {
    173 					tokens[parser->toksuper].size++;
    174 #ifdef JSMN_PARENT_LINKS
    175 					token->parent = parser->toksuper;
    176 #endif
    177 				}
    178 				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
    179 				token->start = parser->pos;
    180 				parser->toksuper = parser->toknext - 1;
    181 				break;
    182 			case '}': case ']':
    183 				if (tokens == NULL)
    184 					break;
    185 				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
    186 #ifdef JSMN_PARENT_LINKS
    187 				if (parser->toknext < 1) {
    188 					return JSMN_ERROR_INVAL;
    189 				}
    190 				token = &tokens[parser->toknext - 1];
    191 				for (;;) {
    192 					if (token->start != -1 && token->end == -1) {
    193 						if (token->type != type) {
    194 							return JSMN_ERROR_INVAL;
    195 						}
    196 						token->end = parser->pos + 1;
    197 						parser->toksuper = token->parent;
    198 						break;
    199 					}
    200 					if (token->parent == -1) {
    201 						if(token->type != type || parser->toksuper == -1) {
    202 							return JSMN_ERROR_INVAL;
    203 						}
    204 						break;
    205 					}
    206 					token = &tokens[token->parent];
    207 				}
    208 #else
    209 				for (i = parser->toknext - 1; i >= 0; i--) {
    210 					token = &tokens[i];
    211 					if (token->start != -1 && token->end == -1) {
    212 						if (token->type != type) {
    213 							return JSMN_ERROR_INVAL;
    214 						}
    215 						parser->toksuper = -1;
    216 						token->end = parser->pos + 1;
    217 						break;
    218 					}
    219 				}
    220 				/* Error if unmatched closing bracket */
    221 				if (i == -1) return JSMN_ERROR_INVAL;
    222 				for (; i >= 0; i--) {
    223 					token = &tokens[i];
    224 					if (token->start != -1 && token->end == -1) {
    225 						parser->toksuper = i;
    226 						break;
    227 					}
    228 				}
    229 #endif
    230 				break;
    231 			case '\"':
    232 				r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
    233 				if (r < 0) return r;
    234 				count++;
    235 				if (parser->toksuper != -1 && tokens != NULL)
    236 					tokens[parser->toksuper].size++;
    237 				break;
    238 			case '\t' : case '\r' : case '\n' : case ' ':
    239 				break;
    240 			case ':':
    241 				parser->toksuper = parser->toknext - 1;
    242 				break;
    243 			case ',':
    244 				if (tokens != NULL && parser->toksuper != -1 &&
    245 						tokens[parser->toksuper].type != JSMN_ARRAY &&
    246 						tokens[parser->toksuper].type != JSMN_OBJECT) {
    247 #ifdef JSMN_PARENT_LINKS
    248 					parser->toksuper = tokens[parser->toksuper].parent;
    249 #else
    250 					for (i = parser->toknext - 1; i >= 0; i--) {
    251 						if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
    252 							if (tokens[i].start != -1 && tokens[i].end == -1) {
    253 								parser->toksuper = i;
    254 								break;
    255 							}
    256 						}
    257 					}
    258 #endif
    259 				}
    260 				break;
    261 #ifdef JSMN_STRICT
    262 			/* In strict mode primitives are: numbers and booleans */
    263 			case '-': case '0': case '1' : case '2': case '3' : case '4':
    264 			case '5': case '6': case '7' : case '8': case '9':
    265 			case 't': case 'f': case 'n' :
    266 				/* And they must not be keys of the object */
    267 				if (tokens != NULL && parser->toksuper != -1) {
    268 					jsmntok_t *t = &tokens[parser->toksuper];
    269 					if (t->type == JSMN_OBJECT ||
    270 							(t->type == JSMN_STRING && t->size != 0)) {
    271 						return JSMN_ERROR_INVAL;
    272 					}
    273 				}
    274 #else
    275 			/* In non-strict mode every unquoted value is a primitive */
    276 			default:
    277 #endif
    278 				r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
    279 				if (r < 0) return r;
    280 				count++;
    281 				if (parser->toksuper != -1 && tokens != NULL)
    282 					tokens[parser->toksuper].size++;
    283 				break;
    284 
    285 #ifdef JSMN_STRICT
    286 			/* Unexpected char in strict mode */
    287 			default:
    288 				return JSMN_ERROR_INVAL;
    289 #endif
    290 		}
    291 	}
    292 
    293 	if (tokens != NULL) {
    294 		for (i = parser->toknext - 1; i >= 0; i--) {
    295 			/* Unmatched opened object or array */
    296 			if (tokens[i].start != -1 && tokens[i].end == -1) {
    297 				return JSMN_ERROR_PART;
    298 			}
    299 		}
    300 	}
    301 
    302 	return count;
    303 }
    304 
    305 /**
    306  * Creates a new parser based over a given  buffer with an array of tokens
    307  * available.
    308  */
    309 void jsmn_init(jsmn_parser *parser) {
    310 	parser->pos = 0;
    311 	parser->toknext = 0;
    312 	parser->toksuper = -1;
    313 }
    314