Fork of my original MQTTGateway

Dependencies:   mbed-http

Committer:
vpcola
Date:
Sat Apr 08 14:43:14 2017 +0000
Revision:
0:a1734fe1ec4b
Initial commit

Who changed what in which revision?

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