Spaces:
Build error
Build error
| // https://github.com/vivkin/gason - pulled January 10, 2016 | |
| const char *jsonStrError(int err) { | |
| switch (err) { | |
| JSON_ERRNO_MAP(XX) | |
| default: | |
| return "unknown"; | |
| } | |
| } | |
| void *JsonAllocator::allocate(size_t size) { | |
| size = (size + 7) & ~7; | |
| if (head && head->used + size <= JSON_ZONE_SIZE) { | |
| char *p = (char *)head + head->used; | |
| head->used += size; | |
| return p; | |
| } | |
| size_t allocSize = sizeof(Zone) + size; | |
| Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); | |
| if (zone == nullptr) | |
| return nullptr; | |
| zone->used = allocSize; | |
| if (allocSize <= JSON_ZONE_SIZE || head == nullptr) { | |
| zone->next = head; | |
| head = zone; | |
| } else { | |
| zone->next = head->next; | |
| head->next = zone; | |
| } | |
| return (char *)zone + sizeof(Zone); | |
| } | |
| void JsonAllocator::deallocate() { | |
| while (head) { | |
| Zone *next = head->next; | |
| free(head); | |
| head = next; | |
| } | |
| } | |
| static inline bool isspace(char c) { | |
| return c == ' ' || (c >= '\t' && c <= '\r'); | |
| } | |
| static inline bool isdelim(char c) { | |
| return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c; | |
| } | |
| static inline bool isdigit(char c) { | |
| return c >= '0' && c <= '9'; | |
| } | |
| static inline bool isxdigit(char c) { | |
| return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F'); | |
| } | |
| static inline int char2int(char c) { | |
| if (c <= '9') | |
| return c - '0'; | |
| return (c & ~' ') - 'A' + 10; | |
| } | |
| static double string2double(char *s, char **endptr) { | |
| char ch = *s; | |
| if (ch == '-') | |
| ++s; | |
| double result = 0; | |
| while (isdigit(*s)) | |
| result = (result * 10) + (*s++ - '0'); | |
| if (*s == '.') { | |
| ++s; | |
| double fraction = 1; | |
| while (isdigit(*s)) { | |
| fraction *= 0.1; | |
| result += (*s++ - '0') * fraction; | |
| } | |
| } | |
| if (*s == 'e' || *s == 'E') { | |
| ++s; | |
| double base = 10; | |
| if (*s == '+') | |
| ++s; | |
| else if (*s == '-') { | |
| ++s; | |
| base = 0.1; | |
| } | |
| unsigned int exponent = 0; | |
| while (isdigit(*s)) | |
| exponent = (exponent * 10) + (*s++ - '0'); | |
| double power = 1; | |
| for (; exponent; exponent >>= 1, base *= base) | |
| if (exponent & 1) | |
| power *= base; | |
| result *= power; | |
| } | |
| *endptr = s; | |
| return ch == '-' ? -result : result; | |
| } | |
| static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) { | |
| if (!tail) | |
| return node->next = node; | |
| node->next = tail->next; | |
| tail->next = node; | |
| return node; | |
| } | |
| static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { | |
| if (tail) { | |
| auto head = tail->next; | |
| tail->next = nullptr; | |
| return JsonValue(tag, head); | |
| } | |
| return JsonValue(tag, nullptr); | |
| } | |
| int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) { | |
| JsonNode *tails[JSON_STACK_SIZE]; | |
| JsonTag tags[JSON_STACK_SIZE]; | |
| char *keys[JSON_STACK_SIZE]; | |
| JsonValue o; | |
| int pos = -1; | |
| bool separator = true; | |
| JsonNode *node; | |
| *endptr = s; | |
| while (*s) { | |
| while (isspace(*s)) { | |
| ++s; | |
| if (!*s) break; | |
| } | |
| *endptr = s++; | |
| switch (**endptr) { | |
| case '-': | |
| if (!isdigit(*s) && *s != '.') { | |
| *endptr = s; | |
| return JSON_BAD_NUMBER; | |
| } | |
| case '0': | |
| case '1': | |
| case '2': | |
| case '3': | |
| case '4': | |
| case '5': | |
| case '6': | |
| case '7': | |
| case '8': | |
| case '9': | |
| o = JsonValue(string2double(*endptr, &s)); | |
| if (!isdelim(*s)) { | |
| *endptr = s; | |
| return JSON_BAD_NUMBER; | |
| } | |
| break; | |
| case '"': | |
| o = JsonValue(JSON_STRING, s); | |
| for (char *it = s; *s; ++it, ++s) { | |
| int c = *it = *s; | |
| if (c == '\\') { | |
| c = *++s; | |
| switch (c) { | |
| case '\\': | |
| case '"': | |
| case '/': | |
| *it = c; | |
| break; | |
| case 'b': | |
| *it = '\b'; | |
| break; | |
| case 'f': | |
| *it = '\f'; | |
| break; | |
| case 'n': | |
| *it = '\n'; | |
| break; | |
| case 'r': | |
| *it = '\r'; | |
| break; | |
| case 't': | |
| *it = '\t'; | |
| break; | |
| case 'u': | |
| c = 0; | |
| for (int i = 0; i < 4; ++i) { | |
| if (isxdigit(*++s)) { | |
| c = c * 16 + char2int(*s); | |
| } else { | |
| *endptr = s; | |
| return JSON_BAD_STRING; | |
| } | |
| } | |
| if (c < 0x80) { | |
| *it = c; | |
| } else if (c < 0x800) { | |
| *it++ = 0xC0 | (c >> 6); | |
| *it = 0x80 | (c & 0x3F); | |
| } else { | |
| *it++ = 0xE0 | (c >> 12); | |
| *it++ = 0x80 | ((c >> 6) & 0x3F); | |
| *it = 0x80 | (c & 0x3F); | |
| } | |
| break; | |
| default: | |
| *endptr = s; | |
| return JSON_BAD_STRING; | |
| } | |
| } else if ((unsigned int)c < ' ' || c == '\x7F') { | |
| *endptr = s; | |
| return JSON_BAD_STRING; | |
| } else if (c == '"') { | |
| *it = 0; | |
| ++s; | |
| break; | |
| } | |
| } | |
| if (!isdelim(*s)) { | |
| *endptr = s; | |
| return JSON_BAD_STRING; | |
| } | |
| break; | |
| case 't': | |
| if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) | |
| return JSON_BAD_IDENTIFIER; | |
| o = JsonValue(JSON_TRUE); | |
| s += 3; | |
| break; | |
| case 'f': | |
| if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) | |
| return JSON_BAD_IDENTIFIER; | |
| o = JsonValue(JSON_FALSE); | |
| s += 4; | |
| break; | |
| case 'n': | |
| if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) | |
| return JSON_BAD_IDENTIFIER; | |
| o = JsonValue(JSON_NULL); | |
| s += 3; | |
| break; | |
| case ']': | |
| if (pos == -1) | |
| return JSON_STACK_UNDERFLOW; | |
| if (tags[pos] != JSON_ARRAY) | |
| return JSON_MISMATCH_BRACKET; | |
| o = listToValue(JSON_ARRAY, tails[pos--]); | |
| break; | |
| case '}': | |
| if (pos == -1) | |
| return JSON_STACK_UNDERFLOW; | |
| if (tags[pos] != JSON_OBJECT) | |
| return JSON_MISMATCH_BRACKET; | |
| if (keys[pos] != nullptr) | |
| return JSON_UNEXPECTED_CHARACTER; | |
| o = listToValue(JSON_OBJECT, tails[pos--]); | |
| break; | |
| case '[': | |
| if (++pos == JSON_STACK_SIZE) | |
| return JSON_STACK_OVERFLOW; | |
| tails[pos] = nullptr; | |
| tags[pos] = JSON_ARRAY; | |
| keys[pos] = nullptr; | |
| separator = true; | |
| continue; | |
| case '{': | |
| if (++pos == JSON_STACK_SIZE) | |
| return JSON_STACK_OVERFLOW; | |
| tails[pos] = nullptr; | |
| tags[pos] = JSON_OBJECT; | |
| keys[pos] = nullptr; | |
| separator = true; | |
| continue; | |
| case ':': | |
| if (separator || keys[pos] == nullptr) | |
| return JSON_UNEXPECTED_CHARACTER; | |
| separator = true; | |
| continue; | |
| case ',': | |
| if (separator || keys[pos] != nullptr) | |
| return JSON_UNEXPECTED_CHARACTER; | |
| separator = true; | |
| continue; | |
| case '\0': | |
| continue; | |
| default: | |
| return JSON_UNEXPECTED_CHARACTER; | |
| } | |
| separator = false; | |
| if (pos == -1) { | |
| *endptr = s; | |
| *value = o; | |
| return JSON_OK; | |
| } | |
| if (tags[pos] == JSON_OBJECT) { | |
| if (!keys[pos]) { | |
| if (o.getTag() != JSON_STRING) | |
| return JSON_UNQUOTED_KEY; | |
| keys[pos] = o.toString(); | |
| continue; | |
| } | |
| if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr) | |
| return JSON_ALLOCATION_FAILURE; | |
| tails[pos] = insertAfter(tails[pos], node); | |
| tails[pos]->key = keys[pos]; | |
| keys[pos] = nullptr; | |
| } else { | |
| if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr) | |
| return JSON_ALLOCATION_FAILURE; | |
| tails[pos] = insertAfter(tails[pos], node); | |
| } | |
| tails[pos]->value = o; | |
| } | |
| return JSON_BREAKING_BAD; | |
| } | |