+++ /dev/null
-// https://github.com/vivkin/gason - pulled January 10, 2016
-#include "gason.h"
-#include <stdlib.h>
-
-#define JSON_ZONE_SIZE 4096
-#define JSON_STACK_SIZE 32
-
-const char *jsonStrError(int err) {
- switch (err) {
-#define XX(no, str) \
- case JSON_##no: \
- return str;
- JSON_ERRNO_MAP(XX)
-#undef 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;
-}