EG version upgrade to 1.3
[ealt-edge.git] / example-apps / PDD / pcb-defect-detection / data / lib_coco / common / gason.cpp
1 // https://github.com/vivkin/gason - pulled January 10, 2016
2 #include "gason.h"
3 #include <stdlib.h>
4
5 #define JSON_ZONE_SIZE 4096
6 #define JSON_STACK_SIZE 32
7
8 const char *jsonStrError(int err) {
9     switch (err) {
10 #define XX(no, str) \
11     case JSON_##no: \
12         return str;
13         JSON_ERRNO_MAP(XX)
14 #undef XX
15     default:
16         return "unknown";
17     }
18 }
19
20 void *JsonAllocator::allocate(size_t size) {
21     size = (size + 7) & ~7;
22
23     if (head && head->used + size <= JSON_ZONE_SIZE) {
24         char *p = (char *)head + head->used;
25         head->used += size;
26         return p;
27     }
28
29     size_t allocSize = sizeof(Zone) + size;
30     Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize);
31     if (zone == nullptr)
32         return nullptr;
33     zone->used = allocSize;
34     if (allocSize <= JSON_ZONE_SIZE || head == nullptr) {
35         zone->next = head;
36         head = zone;
37     } else {
38         zone->next = head->next;
39         head->next = zone;
40     }
41     return (char *)zone + sizeof(Zone);
42 }
43
44 void JsonAllocator::deallocate() {
45     while (head) {
46         Zone *next = head->next;
47         free(head);
48         head = next;
49     }
50 }
51
52 static inline bool isspace(char c) {
53     return c == ' ' || (c >= '\t' && c <= '\r');
54 }
55
56 static inline bool isdelim(char c) {
57     return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c;
58 }
59
60 static inline bool isdigit(char c) {
61     return c >= '0' && c <= '9';
62 }
63
64 static inline bool isxdigit(char c) {
65     return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F');
66 }
67
68 static inline int char2int(char c) {
69     if (c <= '9')
70         return c - '0';
71     return (c & ~' ') - 'A' + 10;
72 }
73
74 static double string2double(char *s, char **endptr) {
75     char ch = *s;
76     if (ch == '-')
77         ++s;
78
79     double result = 0;
80     while (isdigit(*s))
81         result = (result * 10) + (*s++ - '0');
82
83     if (*s == '.') {
84         ++s;
85
86         double fraction = 1;
87         while (isdigit(*s)) {
88             fraction *= 0.1;
89             result += (*s++ - '0') * fraction;
90         }
91     }
92
93     if (*s == 'e' || *s == 'E') {
94         ++s;
95
96         double base = 10;
97         if (*s == '+')
98             ++s;
99         else if (*s == '-') {
100             ++s;
101             base = 0.1;
102         }
103
104         unsigned int exponent = 0;
105         while (isdigit(*s))
106             exponent = (exponent * 10) + (*s++ - '0');
107
108         double power = 1;
109         for (; exponent; exponent >>= 1, base *= base)
110             if (exponent & 1)
111                 power *= base;
112
113         result *= power;
114     }
115
116     *endptr = s;
117     return ch == '-' ? -result : result;
118 }
119
120 static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) {
121     if (!tail)
122         return node->next = node;
123     node->next = tail->next;
124     tail->next = node;
125     return node;
126 }
127
128 static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) {
129     if (tail) {
130         auto head = tail->next;
131         tail->next = nullptr;
132         return JsonValue(tag, head);
133     }
134     return JsonValue(tag, nullptr);
135 }
136
137 int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) {
138     JsonNode *tails[JSON_STACK_SIZE];
139     JsonTag tags[JSON_STACK_SIZE];
140     char *keys[JSON_STACK_SIZE];
141     JsonValue o;
142     int pos = -1;
143     bool separator = true;
144     JsonNode *node;
145     *endptr = s;
146
147     while (*s) {
148         while (isspace(*s)) {
149             ++s;
150             if (!*s) break;
151         }
152         *endptr = s++;
153         switch (**endptr) {
154         case '-':
155             if (!isdigit(*s) && *s != '.') {
156                 *endptr = s;
157                 return JSON_BAD_NUMBER;
158             }
159         case '0':
160         case '1':
161         case '2':
162         case '3':
163         case '4':
164         case '5':
165         case '6':
166         case '7':
167         case '8':
168         case '9':
169             o = JsonValue(string2double(*endptr, &s));
170             if (!isdelim(*s)) {
171                 *endptr = s;
172                 return JSON_BAD_NUMBER;
173             }
174             break;
175         case '"':
176             o = JsonValue(JSON_STRING, s);
177             for (char *it = s; *s; ++it, ++s) {
178                 int c = *it = *s;
179                 if (c == '\\') {
180                     c = *++s;
181                     switch (c) {
182                     case '\\':
183                     case '"':
184                     case '/':
185                         *it = c;
186                         break;
187                     case 'b':
188                         *it = '\b';
189                         break;
190                     case 'f':
191                         *it = '\f';
192                         break;
193                     case 'n':
194                         *it = '\n';
195                         break;
196                     case 'r':
197                         *it = '\r';
198                         break;
199                     case 't':
200                         *it = '\t';
201                         break;
202                     case 'u':
203                         c = 0;
204                         for (int i = 0; i < 4; ++i) {
205                             if (isxdigit(*++s)) {
206                                 c = c * 16 + char2int(*s);
207                             } else {
208                                 *endptr = s;
209                                 return JSON_BAD_STRING;
210                             }
211                         }
212                         if (c < 0x80) {
213                             *it = c;
214                         } else if (c < 0x800) {
215                             *it++ = 0xC0 | (c >> 6);
216                             *it = 0x80 | (c & 0x3F);
217                         } else {
218                             *it++ = 0xE0 | (c >> 12);
219                             *it++ = 0x80 | ((c >> 6) & 0x3F);
220                             *it = 0x80 | (c & 0x3F);
221                         }
222                         break;
223                     default:
224                         *endptr = s;
225                         return JSON_BAD_STRING;
226                     }
227                 } else if ((unsigned int)c < ' ' || c == '\x7F') {
228                     *endptr = s;
229                     return JSON_BAD_STRING;
230                 } else if (c == '"') {
231                     *it = 0;
232                     ++s;
233                     break;
234                 }
235             }
236             if (!isdelim(*s)) {
237                 *endptr = s;
238                 return JSON_BAD_STRING;
239             }
240             break;
241         case 't':
242             if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3])))
243                 return JSON_BAD_IDENTIFIER;
244             o = JsonValue(JSON_TRUE);
245             s += 3;
246             break;
247         case 'f':
248             if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4])))
249                 return JSON_BAD_IDENTIFIER;
250             o = JsonValue(JSON_FALSE);
251             s += 4;
252             break;
253         case 'n':
254             if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3])))
255                 return JSON_BAD_IDENTIFIER;
256             o = JsonValue(JSON_NULL);
257             s += 3;
258             break;
259         case ']':
260             if (pos == -1)
261                 return JSON_STACK_UNDERFLOW;
262             if (tags[pos] != JSON_ARRAY)
263                 return JSON_MISMATCH_BRACKET;
264             o = listToValue(JSON_ARRAY, tails[pos--]);
265             break;
266         case '}':
267             if (pos == -1)
268                 return JSON_STACK_UNDERFLOW;
269             if (tags[pos] != JSON_OBJECT)
270                 return JSON_MISMATCH_BRACKET;
271             if (keys[pos] != nullptr)
272                 return JSON_UNEXPECTED_CHARACTER;
273             o = listToValue(JSON_OBJECT, tails[pos--]);
274             break;
275         case '[':
276             if (++pos == JSON_STACK_SIZE)
277                 return JSON_STACK_OVERFLOW;
278             tails[pos] = nullptr;
279             tags[pos] = JSON_ARRAY;
280             keys[pos] = nullptr;
281             separator = true;
282             continue;
283         case '{':
284             if (++pos == JSON_STACK_SIZE)
285                 return JSON_STACK_OVERFLOW;
286             tails[pos] = nullptr;
287             tags[pos] = JSON_OBJECT;
288             keys[pos] = nullptr;
289             separator = true;
290             continue;
291         case ':':
292             if (separator || keys[pos] == nullptr)
293                 return JSON_UNEXPECTED_CHARACTER;
294             separator = true;
295             continue;
296         case ',':
297             if (separator || keys[pos] != nullptr)
298                 return JSON_UNEXPECTED_CHARACTER;
299             separator = true;
300             continue;
301         case '\0':
302             continue;
303         default:
304             return JSON_UNEXPECTED_CHARACTER;
305         }
306
307         separator = false;
308
309         if (pos == -1) {
310             *endptr = s;
311             *value = o;
312             return JSON_OK;
313         }
314
315         if (tags[pos] == JSON_OBJECT) {
316             if (!keys[pos]) {
317                 if (o.getTag() != JSON_STRING)
318                     return JSON_UNQUOTED_KEY;
319                 keys[pos] = o.toString();
320                 continue;
321             }
322             if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr)
323                 return JSON_ALLOCATION_FAILURE;
324             tails[pos] = insertAfter(tails[pos], node);
325             tails[pos]->key = keys[pos];
326             keys[pos] = nullptr;
327         } else {
328             if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr)
329                 return JSON_ALLOCATION_FAILURE;
330             tails[pos] = insertAfter(tails[pos], node);
331         }
332         tails[pos]->value = o;
333     }
334     return JSON_BREAKING_BAD;
335 }