1 // Distributed under the MIT license. Copyright (c) 2010, Ivan Vashchaev
11 // true if character represent a digit
12 #define IS_DIGIT(c) (c >= '0' && c <= '9')
14 // convert string to integer
15 static char *atoi(char *first, char *last, int *out)
25 else if (*first == '+')
32 for (; first != last && IS_DIGIT(*first); ++first)
34 result = 10 * result + (*first - '0');
41 // convert hexadecimal string to unsigned integer
42 static char *hatoui(char *first, char *last, unsigned int *out)
44 unsigned int result = 0;
45 for (; first != last; ++first)
52 else if (*first >= 'a' && *first <= 'f')
54 digit = *first - 'a' + 10;
56 else if (*first >= 'A' && *first <= 'F')
58 digit = *first - 'A' + 10;
64 result = 16 * result + (unsigned int)digit;
71 // convert string to floating point
72 static char *atof(char *first, char *last, float *out)
83 else if (*first == '+')
91 for (; first != last && IS_DIGIT(*first); ++first)
93 result = 10 * result + (float)(*first - '0');
97 if (first != last && *first == '.')
101 float inv_base = 0.1f;
102 for (; first != last && IS_DIGIT(*first); ++first)
104 result += (float)(*first - '0') * inv_base;
109 // result w\o exponent
113 bool exponent_negative = false;
115 if (first != last && (*first == 'e' || *first == 'E'))
121 exponent_negative = true;
124 else if (*first == '+')
129 for (; first != last && IS_DIGIT(*first); ++first)
131 exponent = 10 * exponent + (*first - '0');
137 float power_of_ten = 10;
138 for (; exponent > 1; exponent--)
143 if (exponent_negative)
145 result /= power_of_ten;
149 result *= power_of_ten;
158 static inline json_value *json_alloc(block_allocator *allocator)
160 json_value *value = (json_value *)allocator->malloc(sizeof(json_value));
161 memset(value, 0, sizeof(json_value));
165 static inline void json_append(json_value *lhs, json_value *rhs)
170 lhs->last_child = lhs->last_child->next_sibling = rhs;
174 lhs->first_child = lhs->last_child = rhs;
178 #define ERROR(it, desc)\
181 *error_line = 1 - escaped_newlines;\
182 for (char *c = it; c != source; --c)\
183 if (*c == '\n') ++*error_line;\
186 #define CHECK_TOP() if (!top) {ERROR(it, "Unexpected character");}
188 json_value *json_parse(char *source, char **error_pos, const char **error_desc, int *error_line, block_allocator *allocator)
190 json_value *root = 0;
196 int escaped_newlines = 0;
201 while (*it == '\x20' || *it == '\x9' || *it == '\xD' || *it == '\xA')
214 json_value *object = json_alloc(allocator);
221 object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY;
223 // skip open character
229 json_append(top, object);
237 ERROR(it, "Second root. Only one root allowed");
246 if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY))
248 ERROR(it, "Mismatch closing brace/bracket");
251 // skip close character
260 if (!top || top->type != JSON_OBJECT)
262 ERROR(it, "Unexpected character");
276 // skip '"' character
283 if ((unsigned char)*it < '\x20')
285 ERROR(first, "Control characters not allowed in strings");
287 else if (*it == '\\')
318 unsigned int codepoint;
319 if (hatoui(it + 2, it + 6, &codepoint) != it + 6)
321 ERROR(it, "Bad unicode codepoint");
324 if (codepoint <= 0x7F)
326 *last = (char)codepoint;
328 else if (codepoint <= 0x7FF)
330 *last++ = (char)(0xC0 | (codepoint >> 6));
331 *last = (char)(0x80 | (codepoint & 0x3F));
333 else if (codepoint <= 0xFFFF)
335 *last++ = (char)(0xE0 | (codepoint >> 12));
336 *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
337 *last = (char)(0x80 | (codepoint & 0x3F));
343 ERROR(first, "Unrecognized escape sequence");
361 if (!name && top->type == JSON_OBJECT)
363 // field name in object
369 json_value *object = json_alloc(allocator);
374 object->type = JSON_STRING;
375 object->string_value = first;
377 json_append(top, object);
388 // new null/bool value
389 json_value *object = json_alloc(allocator);
395 if (it[0] == 'n' && it[1] == 'u' && it[2] == 'l' && it[3] == 'l')
397 object->type = JSON_NULL;
401 else if (it[0] == 't' && it[1] == 'r' && it[2] == 'u' && it[3] == 'e')
403 object->type = JSON_BOOL;
404 object->int_value = 1;
408 else if (it[0] == 'f' && it[1] == 'a' && it[2] == 'l' && it[3] == 's' && it[4] == 'e')
410 object->type = JSON_BOOL;
411 object->int_value = 0;
416 ERROR(it, "Unknown identifier");
419 json_append(top, object);
438 json_value *object = json_alloc(allocator);
443 object->type = JSON_INT;
446 while (*it != '\x20' && *it != '\x9' && *it != '\xD' && *it != '\xA' && *it != ',' && *it != ']' && *it != '}')
448 if (*it == '.' || *it == 'e' || *it == 'E')
450 object->type = JSON_FLOAT;
455 if (object->type == JSON_INT && atoi(first, it, &object->int_value) != it)
457 ERROR(first, "Bad integer number");
460 if (object->type == JSON_FLOAT && atof(first, it, &object->float_value) != it)
462 ERROR(first, "Bad float number");
465 json_append(top, object);
470 ERROR(it, "Unexpected character");
476 ERROR(it, "Not all objects/arrays have been properly closed");
482 } // end namespace mc_json