1 // Distributed under the MIT license. Copyright (c) 2010, Ivan Vashchaev
\r
6 // true if character represent a digit
\r
7 #define IS_DIGIT(c) (c >= '0' && c <= '9')
\r
9 // convert string to integer
\r
10 static char *atoi(char *first, char *last, int *out)
\r
20 else if (*first == '+')
\r
27 for (; first != last && IS_DIGIT(*first); ++first)
\r
29 result = 10 * result + (*first - '0');
\r
31 *out = result * sign;
\r
36 // convert hexadecimal string to unsigned integer
\r
37 static char *hatoui(char *first, char *last, unsigned int *out)
\r
39 unsigned int result = 0;
\r
40 for (; first != last; ++first)
\r
43 if (IS_DIGIT(*first))
\r
45 digit = *first - '0';
\r
47 else if (*first >= 'a' && *first <= 'f')
\r
49 digit = *first - 'a' + 10;
\r
51 else if (*first >= 'A' && *first <= 'F')
\r
53 digit = *first - 'A' + 10;
\r
59 result = 16 * result + (unsigned int)digit;
\r
66 // convert string to floating point
\r
67 static char *atof(char *first, char *last, float *out)
\r
78 else if (*first == '+')
\r
86 for (; first != last && IS_DIGIT(*first); ++first)
\r
88 result = 10 * result + (float)(*first - '0');
\r
92 if (first != last && *first == '.')
\r
96 float inv_base = 0.1f;
\r
97 for (; first != last && IS_DIGIT(*first); ++first)
\r
99 result += (float)(*first - '0') * inv_base;
\r
104 // result w\o exponent
\r
108 bool exponent_negative = false;
\r
110 if (first != last && (*first == 'e' || *first == 'E'))
\r
116 exponent_negative = true;
\r
119 else if (*first == '+')
\r
124 for (; first != last && IS_DIGIT(*first); ++first)
\r
126 exponent = 10 * exponent + (*first - '0');
\r
132 float power_of_ten = 10;
\r
133 for (; exponent > 1; exponent--)
\r
135 power_of_ten *= 10;
\r
138 if (exponent_negative)
\r
140 result /= power_of_ten;
\r
144 result *= power_of_ten;
\r
153 static inline json_value *json_alloc(block_allocator *allocator)
\r
155 json_value *value = (json_value *)allocator->malloc(sizeof(json_value));
\r
156 memset(value, 0, sizeof(json_value));
\r
160 static inline void json_append(json_value *lhs, json_value *rhs)
\r
163 if (lhs->last_child)
\r
165 lhs->last_child = lhs->last_child->next_sibling = rhs;
\r
169 lhs->first_child = lhs->last_child = rhs;
\r
173 #define ERROR(it, desc)\
\r
175 *error_desc = desc;\
\r
176 *error_line = 1 - escaped_newlines;\
\r
177 for (char *c = it; c != source; --c)\
\r
178 if (*c == '\n') ++*error_line;\
\r
181 #define CHECK_TOP() if (!top) {ERROR(it, "Unexpected character");}
\r
183 json_value *json_parse(char *source, char **error_pos, const char **error_desc, int *error_line, block_allocator *allocator)
\r
185 json_value *root = 0;
\r
186 json_value *top = 0;
\r
191 int escaped_newlines = 0;
\r
195 // skip white space
\r
196 while (*it == '\x20' || *it == '\x9' || *it == '\xD' || *it == '\xA')
\r
208 // create new value
\r
209 json_value *object = json_alloc(allocator);
\r
212 object->name = name;
\r
216 object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY;
\r
218 // skip open character
\r
221 // set top and root
\r
224 json_append(top, object);
\r
232 ERROR(it, "Second root. Only one root allowed");
\r
241 if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY))
\r
243 ERROR(it, "Mismatch closing brace/bracket");
\r
246 // skip close character
\r
255 if (!top || top->type != JSON_OBJECT)
\r
257 ERROR(it, "Unexpected character");
\r
271 // skip '"' character
\r
278 if ((unsigned char)*it < '\x20')
\r
280 ERROR(first, "Control characters not allowed in strings");
\r
282 else if (*it == '\\')
\r
303 ++escaped_newlines;
\r
313 unsigned int codepoint;
\r
314 if (hatoui(it + 2, it + 6, &codepoint) != it + 6)
\r
316 ERROR(it, "Bad unicode codepoint");
\r
319 if (codepoint <= 0x7F)
\r
321 *last = (char)codepoint;
\r
323 else if (codepoint <= 0x7FF)
\r
325 *last++ = (char)(0xC0 | (codepoint >> 6));
\r
326 *last = (char)(0x80 | (codepoint & 0x3F));
\r
328 else if (codepoint <= 0xFFFF)
\r
330 *last++ = (char)(0xE0 | (codepoint >> 12));
\r
331 *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
\r
332 *last = (char)(0x80 | (codepoint & 0x3F));
\r
338 ERROR(first, "Unrecognized escape sequence");
\r
344 else if (*it == '"')
\r
356 if (!name && top->type == JSON_OBJECT)
\r
358 // field name in object
\r
363 // new string value
\r
364 json_value *object = json_alloc(allocator);
\r
366 object->name = name;
\r
369 object->type = JSON_STRING;
\r
370 object->string_value = first;
\r
372 json_append(top, object);
\r
383 // new null/bool value
\r
384 json_value *object = json_alloc(allocator);
\r
386 object->name = name;
\r
390 if (it[0] == 'n' && it[1] == 'u' && it[2] == 'l' && it[3] == 'l')
\r
392 object->type = JSON_NULL;
\r
396 else if (it[0] == 't' && it[1] == 'r' && it[2] == 'u' && it[3] == 'e')
\r
398 object->type = JSON_BOOL;
\r
399 object->int_value = 1;
\r
403 else if (it[0] == 'f' && it[1] == 'a' && it[2] == 'l' && it[3] == 's' && it[4] == 'e')
\r
405 object->type = JSON_BOOL;
\r
406 object->int_value = 0;
\r
411 ERROR(it, "Unknown identifier");
\r
414 json_append(top, object);
\r
432 // new number value
\r
433 json_value *object = json_alloc(allocator);
\r
435 object->name = name;
\r
438 object->type = JSON_INT;
\r
441 while (*it != '\x20' && *it != '\x9' && *it != '\xD' && *it != '\xA' && *it != ',' && *it != ']' && *it != '}')
\r
443 if (*it == '.' || *it == 'e' || *it == 'E')
\r
445 object->type = JSON_FLOAT;
\r
450 if (object->type == JSON_INT && atoi(first, it, &object->int_value) != it)
\r
452 ERROR(first, "Bad integer number");
\r
455 if (object->type == JSON_FLOAT && atof(first, it, &object->float_value) != it)
\r
457 ERROR(first, "Bad float number");
\r
460 json_append(top, object);
\r
465 ERROR(it, "Unexpected character");
\r
471 ERROR(it, "Not all objects/arrays have been properly closed");
\r