json lib

Dependents:   grove_stream_jpa_sd2 grove_stream_jpa_sd2 grove_stream_jpa_sd2-2 grove_stream_jpa_sd2-3 ... more

Committer:
mercurywaters
Date:
Fri May 13 06:07:34 2016 +0000
Revision:
0:7f4a18b3fd82
Child:
3:fab591fca1e7
First cut code commit

Who changed what in which revision?

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