Fork of my MQTTGateway

Dependencies:   mbed-http

Committer:
vpcola
Date:
Sat Apr 08 14:45:51 2017 +0000
Revision:
0:f1d3878b8dd9
Initial commit

Who changed what in which revision?

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