cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

jsmn.c (7855B)


      1/*
      2 * Copyright (c) 2010 Serge A. Zaitsev
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a copy
      5 * of this software and associated documentation files (the "Software"), to deal
      6 * in the Software without restriction, including without limitation the rights
      7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 * copies of the Software, and to permit persons to whom the Software is
      9 * furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 * THE SOFTWARE.
     21 *
     22 * Slightly modified by AK to not assume 0 terminated input.
     23 */
     24
     25#include <stdlib.h>
     26#include "jsmn.h"
     27#define JSMN_STRICT
     28
     29/*
     30 * Allocates a fresh unused token from the token pool.
     31 */
     32static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
     33				   jsmntok_t *tokens, size_t num_tokens)
     34{
     35	jsmntok_t *tok;
     36
     37	if ((unsigned)parser->toknext >= num_tokens)
     38		return NULL;
     39	tok = &tokens[parser->toknext++];
     40	tok->start = tok->end = -1;
     41	tok->size = 0;
     42	return tok;
     43}
     44
     45/*
     46 * Fills token type and boundaries.
     47 */
     48static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
     49			    int start, int end)
     50{
     51	token->type = type;
     52	token->start = start;
     53	token->end = end;
     54	token->size = 0;
     55}
     56
     57/*
     58 * Fills next available token with JSON primitive.
     59 */
     60static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
     61				      size_t len,
     62				      jsmntok_t *tokens, size_t num_tokens)
     63{
     64	jsmntok_t *token;
     65	int start;
     66
     67	start = parser->pos;
     68
     69	for (; parser->pos < len; parser->pos++) {
     70		switch (js[parser->pos]) {
     71#ifndef JSMN_STRICT
     72		/*
     73		 * In strict mode primitive must be followed by ","
     74		 * or "}" or "]"
     75		 */
     76		case ':':
     77#endif
     78		case '\t':
     79		case '\r':
     80		case '\n':
     81		case ' ':
     82		case ',':
     83		case ']':
     84		case '}':
     85			goto found;
     86		default:
     87			break;
     88		}
     89		if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
     90			parser->pos = start;
     91			return JSMN_ERROR_INVAL;
     92		}
     93	}
     94#ifdef JSMN_STRICT
     95	/*
     96	 * In strict mode primitive must be followed by a
     97	 * comma/object/array.
     98	 */
     99	parser->pos = start;
    100	return JSMN_ERROR_PART;
    101#endif
    102
    103found:
    104	token = jsmn_alloc_token(parser, tokens, num_tokens);
    105	if (token == NULL) {
    106		parser->pos = start;
    107		return JSMN_ERROR_NOMEM;
    108	}
    109	jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
    110	parser->pos--; /* parent sees closing brackets */
    111	return JSMN_SUCCESS;
    112}
    113
    114/*
    115 * Fills next token with JSON string.
    116 */
    117static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
    118				   size_t len,
    119				   jsmntok_t *tokens, size_t num_tokens)
    120{
    121	jsmntok_t *token;
    122	int start = parser->pos;
    123
    124	/* Skip starting quote */
    125	parser->pos++;
    126
    127	for (; parser->pos < len; parser->pos++) {
    128		char c = js[parser->pos];
    129
    130		/* Quote: end of string */
    131		if (c == '\"') {
    132			token = jsmn_alloc_token(parser, tokens, num_tokens);
    133			if (token == NULL) {
    134				parser->pos = start;
    135				return JSMN_ERROR_NOMEM;
    136			}
    137			jsmn_fill_token(token, JSMN_STRING, start+1,
    138					parser->pos);
    139			return JSMN_SUCCESS;
    140		}
    141
    142		/* Backslash: Quoted symbol expected */
    143		if (c == '\\') {
    144			parser->pos++;
    145			switch (js[parser->pos]) {
    146				/* Allowed escaped symbols */
    147			case '\"':
    148			case '/':
    149			case '\\':
    150			case 'b':
    151			case 'f':
    152			case 'r':
    153			case 'n':
    154			case 't':
    155				break;
    156				/* Allows escaped symbol \uXXXX */
    157			case 'u':
    158				/* TODO */
    159				break;
    160				/* Unexpected symbol */
    161			default:
    162				parser->pos = start;
    163				return JSMN_ERROR_INVAL;
    164			}
    165		}
    166	}
    167	parser->pos = start;
    168	return JSMN_ERROR_PART;
    169}
    170
    171/*
    172 * Parse JSON string and fill tokens.
    173 */
    174jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
    175		     jsmntok_t *tokens, unsigned int num_tokens)
    176{
    177	jsmnerr_t r;
    178	int i;
    179	jsmntok_t *token;
    180#ifdef JSMN_STRICT
    181	/*
    182	 * Keeps track of whether a new object/list/primitive is expected. New items are only
    183	 * allowed after an opening brace, comma or colon. A closing brace after a comma is not
    184	 * valid JSON.
    185	 */
    186	int expecting_item = 1;
    187#endif
    188
    189	for (; parser->pos < len; parser->pos++) {
    190		char c;
    191		jsmntype_t type;
    192
    193		c = js[parser->pos];
    194		switch (c) {
    195		case '{':
    196		case '[':
    197#ifdef JSMN_STRICT
    198			if (!expecting_item)
    199				return JSMN_ERROR_INVAL;
    200#endif
    201			token = jsmn_alloc_token(parser, tokens, num_tokens);
    202			if (token == NULL)
    203				return JSMN_ERROR_NOMEM;
    204			if (parser->toksuper != -1)
    205				tokens[parser->toksuper].size++;
    206			token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
    207			token->start = parser->pos;
    208			parser->toksuper = parser->toknext - 1;
    209			break;
    210		case '}':
    211		case ']':
    212#ifdef JSMN_STRICT
    213			if (expecting_item)
    214				return JSMN_ERROR_INVAL;
    215#endif
    216			type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
    217			for (i = parser->toknext - 1; i >= 0; i--) {
    218				token = &tokens[i];
    219				if (token->start != -1 && token->end == -1) {
    220					if (token->type != type)
    221						return JSMN_ERROR_INVAL;
    222					parser->toksuper = -1;
    223					token->end = parser->pos + 1;
    224					break;
    225				}
    226			}
    227			/* Error if unmatched closing bracket */
    228			if (i == -1)
    229				return JSMN_ERROR_INVAL;
    230			for (; i >= 0; i--) {
    231				token = &tokens[i];
    232				if (token->start != -1 && token->end == -1) {
    233					parser->toksuper = i;
    234					break;
    235				}
    236			}
    237			break;
    238		case '\"':
    239#ifdef JSMN_STRICT
    240			if (!expecting_item)
    241				return JSMN_ERROR_INVAL;
    242			expecting_item = 0;
    243#endif
    244			r = jsmn_parse_string(parser, js, len, tokens,
    245					      num_tokens);
    246			if (r < 0)
    247				return r;
    248			if (parser->toksuper != -1)
    249				tokens[parser->toksuper].size++;
    250			break;
    251		case '\t':
    252		case '\r':
    253		case '\n':
    254		case ' ':
    255			break;
    256#ifdef JSMN_STRICT
    257		case ':':
    258		case ',':
    259			if (expecting_item)
    260				return JSMN_ERROR_INVAL;
    261			expecting_item = 1;
    262			break;
    263			/*
    264			 * In strict mode primitives are:
    265			 * numbers and booleans.
    266			 */
    267		case '-':
    268		case '0':
    269		case '1':
    270		case '2':
    271		case '3':
    272		case '4':
    273		case '5':
    274		case '6':
    275		case '7':
    276		case '8':
    277		case '9':
    278		case 't':
    279		case 'f':
    280		case 'n':
    281#else
    282		case ':':
    283		case ',':
    284			break;
    285			/*
    286			 * In non-strict mode every unquoted value
    287			 * is a primitive.
    288			 */
    289			/*FALL THROUGH */
    290		default:
    291#endif
    292
    293#ifdef JSMN_STRICT
    294			if (!expecting_item)
    295				return JSMN_ERROR_INVAL;
    296			expecting_item = 0;
    297#endif
    298			r = jsmn_parse_primitive(parser, js, len, tokens,
    299						 num_tokens);
    300			if (r < 0)
    301				return r;
    302			if (parser->toksuper != -1)
    303				tokens[parser->toksuper].size++;
    304			break;
    305
    306#ifdef JSMN_STRICT
    307			/* Unexpected char in strict mode */
    308		default:
    309			return JSMN_ERROR_INVAL;
    310#endif
    311		}
    312	}
    313
    314	for (i = parser->toknext - 1; i >= 0; i--) {
    315		/* Unmatched opened object or array */
    316		if (tokens[i].start != -1 && tokens[i].end == -1)
    317			return JSMN_ERROR_PART;
    318	}
    319
    320#ifdef JSMN_STRICT
    321	return expecting_item ? JSMN_ERROR_INVAL : JSMN_SUCCESS;
    322#else
    323	return JSMN_SUCCESS;
    324#endif
    325}
    326
    327/*
    328 * Creates a new parser based over a given  buffer with an array of tokens
    329 * available.
    330 */
    331void jsmn_init(jsmn_parser *parser)
    332{
    333	parser->pos = 0;
    334	parser->toknext = 0;
    335	parser->toksuper = -1;
    336}
    337
    338const char *jsmn_strerror(jsmnerr_t err)
    339{
    340	switch (err) {
    341	case JSMN_ERROR_NOMEM:
    342		return "No enough tokens";
    343	case JSMN_ERROR_INVAL:
    344		return "Invalid character inside JSON string";
    345	case JSMN_ERROR_PART:
    346		return "The string is not a full JSON packet, more bytes expected";
    347	case JSMN_SUCCESS:
    348		return "Success";
    349	default:
    350		return "Unknown json error";
    351	}
    352}