File Coverage

jsonsl/jsonsl.c
Criterion Covered Total %
statement 416 506 82.2
branch 307 616 49.8
condition n/a
subroutine n/a
pod n/a
total 723 1122 64.4


line stmt bran cond sub pod time code
1             /* Copyright (C) 2012-2015 Mark Nunberg.
2             *
3             * See included LICENSE file for license details.
4             */
5              
6             #include "jsonsl.h"
7             #include
8             #include
9             #include
10              
11             #ifdef JSONSL_USE_METRICS
12             #define XMETRICS \
13             X(STRINGY_INSIGNIFICANT) \
14             X(STRINGY_SLOWPATH) \
15             X(ALLOWED_WHITESPACE) \
16             X(QUOTE_FASTPATH) \
17             X(SPECIAL_FASTPATH) \
18             X(SPECIAL_WSPOP) \
19             X(SPECIAL_SLOWPATH) \
20             X(GENERIC) \
21             X(STRUCTURAL_TOKEN) \
22             X(SPECIAL_SWITCHFIRST) \
23             X(STRINGY_CATCH) \
24             X(ESCAPES) \
25             X(TOTAL) \
26              
27             struct jsonsl_metrics_st {
28             #define X(m) \
29             unsigned long metric_##m;
30             XMETRICS
31             #undef X
32             };
33              
34             static struct jsonsl_metrics_st GlobalMetrics = { 0 };
35             static unsigned long GenericCounter[0x100] = { 0 };
36             static unsigned long StringyCatchCounter[0x100] = { 0 };
37              
38             #define INCR_METRIC(m) \
39             GlobalMetrics.metric_##m++;
40              
41             #define INCR_GENERIC(c) \
42             INCR_METRIC(GENERIC); \
43             GenericCounter[c]++; \
44              
45             #define INCR_STRINGY_CATCH(c) \
46             INCR_METRIC(STRINGY_CATCH); \
47             StringyCatchCounter[c]++;
48              
49             JSONSL_API
50             void jsonsl_dump_global_metrics(void)
51             {
52             int ii;
53             printf("JSONSL Metrics:\n");
54             #define X(m) \
55             printf("\t%-30s %20lu (%0.2f%%)\n", #m, GlobalMetrics.metric_##m, \
56             (float)((float)(GlobalMetrics.metric_##m/(float)GlobalMetrics.metric_TOTAL)) * 100);
57             XMETRICS
58             #undef X
59             printf("Generic Characters:\n");
60             for (ii = 0; ii < 0xff; ii++) {
61             if (GenericCounter[ii]) {
62             printf("\t[ %c ] %lu\n", ii, GenericCounter[ii]);
63             }
64             }
65             printf("Weird string loop\n");
66             for (ii = 0; ii < 0xff; ii++) {
67             if (StringyCatchCounter[ii]) {
68             printf("\t[ %c ] %lu\n", ii, StringyCatchCounter[ii]);
69             }
70             }
71             }
72              
73             #else
74             #define INCR_METRIC(m)
75             #define INCR_GENERIC(c)
76             #define INCR_STRINGY_CATCH(c)
77             JSONSL_API
78 0           void jsonsl_dump_global_metrics(void) { }
79             #endif /* JSONSL_USE_METRICS */
80              
81             #define CASE_DIGITS \
82             case '1': \
83             case '2': \
84             case '3': \
85             case '4': \
86             case '5': \
87             case '6': \
88             case '7': \
89             case '8': \
90             case '9': \
91             case '0':
92              
93             static unsigned extract_special(unsigned);
94             static int is_special_end(unsigned);
95             static int is_allowed_whitespace(unsigned);
96             static int is_allowed_escape(unsigned);
97             static char get_escape_equiv(unsigned);
98              
99             JSONSL_API
100 33           jsonsl_t jsonsl_new(int nlevels)
101             {
102 33           struct jsonsl_st *jsn = (struct jsonsl_st *)
103 33           calloc(1, sizeof (*jsn) +
104 33           ( (nlevels-1) * sizeof (struct jsonsl_state_st) )
105             );
106              
107 33           jsn->levels_max = nlevels;
108 33           jsn->max_callback_level = -1;
109 33           jsonsl_reset(jsn);
110 33           return jsn;
111             }
112              
113             JSONSL_API
114 67           void jsonsl_reset(jsonsl_t jsn)
115             {
116             unsigned int ii;
117 67           jsn->tok_last = 0;
118 67           jsn->can_insert = 1;
119 67           jsn->pos = 0;
120 67           jsn->level = 0;
121 67           jsn->stopfl = 0;
122 67           jsn->in_escape = 0;
123 67           jsn->expecting = 0;
124              
125 67           memset(jsn->stack, 0, (jsn->levels_max * sizeof (struct jsonsl_state_st)));
126              
127 33026 100         for (ii = 0; ii < jsn->levels_max; ii++) {
128 32959           jsn->stack[ii].level = ii;
129             }
130 67           }
131              
132             JSONSL_API
133 26           void jsonsl_destroy(jsonsl_t jsn)
134             {
135 26 50         if (jsn) {
136 26           free(jsn);
137             }
138 26           }
139              
140             JSONSL_API
141             void
142 57           jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
143             {
144              
145             #define INVOKE_ERROR(eb) \
146             if (jsn->error_callback(jsn, JSONSL_ERROR_##eb, state, (char*)c)) { \
147             goto GT_AGAIN; \
148             } \
149             return;
150              
151             #define STACK_PUSH \
152             if (jsn->level >= (levels_max-1)) { \
153             jsn->error_callback(jsn, JSONSL_ERROR_LEVELS_EXCEEDED, state, (char*)c); \
154             return; \
155             } \
156             state = jsn->stack + (++jsn->level); \
157             state->ignore_callback = jsn->stack[jsn->level-1].ignore_callback; \
158             state->pos_begin = jsn->pos;
159              
160             #define STACK_POP_NOPOS \
161             state->pos_cur = jsn->pos; \
162             state = jsn->stack + (--jsn->level);
163              
164              
165             #define STACK_POP \
166             STACK_POP_NOPOS; \
167             state->pos_cur = jsn->pos;
168              
169             #define CALLBACK_AND_POP_NOPOS(T) \
170             state->pos_cur = jsn->pos; \
171             DO_CALLBACK(T, POP); \
172             state->nescapes = 0; \
173             state = jsn->stack + (--jsn->level);
174              
175             #define CALLBACK_AND_POP(T) \
176             CALLBACK_AND_POP_NOPOS(T); \
177             state->pos_cur = jsn->pos;
178              
179             #define SPECIAL_POP \
180             CALLBACK_AND_POP(SPECIAL); \
181             jsn->expecting = 0; \
182             jsn->tok_last = 0; \
183              
184             #define CUR_CHAR (*(jsonsl_uchar_t*)c)
185              
186             #define DO_CALLBACK(T, action) \
187             if (jsn->call_##T && \
188             jsn->max_callback_level > state->level && \
189             state->ignore_callback == 0) { \
190             \
191             if (jsn->action_callback_##action) { \
192             jsn->action_callback_##action(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \
193             } else if (jsn->action_callback) { \
194             jsn->action_callback(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \
195             } \
196             if (jsn->stopfl) { return; } \
197             }
198              
199             /**
200             * Verifies that we are able to insert the (non-string) item into a hash.
201             */
202             #define ENSURE_HVAL \
203             if (state->nelem % 2 == 0 && state->type == JSONSL_T_OBJECT) { \
204             INVOKE_ERROR(HKEY_EXPECTED); \
205             }
206              
207             #define VERIFY_SPECIAL(lit) \
208             if (CUR_CHAR != (lit)[jsn->pos - state->pos_begin]) { \
209             INVOKE_ERROR(SPECIAL_EXPECTED); \
210             }
211              
212             #define STATE_SPECIAL_LENGTH \
213             (state)->nescapes
214              
215             #define IS_NORMAL_NUMBER \
216             ((state)->special_flags == JSONSL_SPECIALf_UNSIGNED || \
217             (state)->special_flags == JSONSL_SPECIALf_SIGNED)
218              
219             #define STATE_NUM_LAST jsn->tok_last
220              
221 57           const jsonsl_uchar_t *c = (jsonsl_uchar_t*)bytes;
222 57           size_t levels_max = jsn->levels_max;
223 57           struct jsonsl_state_st *state = jsn->stack + jsn->level;
224             static int chrt_string_nopass[0x100] = { JSONSL_CHARTABLE_string_nopass };
225 57           jsn->base = bytes;
226              
227 7576 100         for (; nbytes; nbytes--, jsn->pos++, c++) {
228             unsigned state_type;
229             INCR_METRIC(TOTAL);
230             /* Special escape handling for some stuff */
231 7533 100         if (jsn->in_escape) {
232 13           jsn->in_escape = 0;
233 13 50         if (!is_allowed_escape(CUR_CHAR)) {
234 0 0         INVOKE_ERROR(ESCAPE_INVALID);
235 13 100         } else if (CUR_CHAR == 'u') {
236 4 50         DO_CALLBACK(UESCAPE, UESCAPE);
    0          
    0          
    0          
    0          
    0          
237 4 50         if (jsn->return_UESCAPE) {
238 0           return;
239             }
240             }
241 13           goto GT_NEXT;
242             }
243             GT_AGAIN:
244             /**
245             * Several fast-tracks for common cases:
246             */
247 7520           state_type = state->type;
248 7520 100         if (state_type & JSONSL_Tf_STRINGY) {
249             /* check if our character cannot ever change our current string state
250             * or throw an error
251             */
252 1633 100         if (
253             #ifdef JSONSL_USE_WCHAR
254             CUR_CHAR >= 0x100 ||
255             #endif /* JSONSL_USE_WCHAR */
256 1633           (!chrt_string_nopass[CUR_CHAR & 0xff])) {
257             INCR_METRIC(STRINGY_INSIGNIFICANT);
258 506           goto GT_NEXT;
259 1127 100         } else if (CUR_CHAR == '"') {
260 1113           goto GT_QUOTE;
261 14 100         } else if (CUR_CHAR == '\\') {
262 13           goto GT_ESCAPE;
263             } else {
264 1 0         INVOKE_ERROR(WEIRD_WHITESPACE);
265             }
266             INCR_METRIC(STRINGY_SLOWPATH);
267              
268 5887 100         } else if (state_type == JSONSL_T_SPECIAL) {
269             /* Fast track for signed/unsigned */
270 137 100         if (IS_NORMAL_NUMBER) {
    100          
271 31 100         if (isdigit(CUR_CHAR)) {
272 7           state->nelem = (state->nelem * 10) + (CUR_CHAR-0x30);
273 7           goto GT_NEXT;
274             } else {
275 24           goto GT_SPECIAL_NUMERIC;
276             }
277              
278 106 100         } else if (state->special_flags == JSONSL_SPECIALf_DASH) {
279 7 100         if (!isdigit(CUR_CHAR)) {
280 1 0         INVOKE_ERROR(INVALID_NUMBER);
281             }
282              
283 6 100         if (CUR_CHAR == '0') {
284 2           state->special_flags = JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED;
285 4 50         } else if (isdigit(CUR_CHAR)) {
286 4           state->special_flags = JSONSL_SPECIALf_SIGNED;
287 4           state->nelem = CUR_CHAR - 0x30;
288             } else {
289 0 0         INVOKE_ERROR(INVALID_NUMBER);
290             }
291              
292 6           goto GT_NEXT;
293              
294 99 100         } else if (state->special_flags == JSONSL_SPECIALf_ZERO) {
295 7 100         if (isdigit(CUR_CHAR)) {
296             /* Following a zero! */
297 2 0         INVOKE_ERROR(INVALID_NUMBER);
298             }
299             /* Unset the 'zero' flag: */
300 5 50         if (state->special_flags & JSONSL_SPECIALf_SIGNED) {
301 0           state->special_flags = JSONSL_SPECIALf_SIGNED;
302             } else {
303 5           state->special_flags = JSONSL_SPECIALf_UNSIGNED;
304             }
305 5           goto GT_SPECIAL_NUMERIC;
306             }
307              
308 92 100         if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
309             GT_SPECIAL_NUMERIC:
310 90           switch (CUR_CHAR) {
311             CASE_DIGITS
312 37           STATE_NUM_LAST = '1';
313 37           goto GT_NEXT;
314              
315             case '.':
316 9 50         if (state->special_flags & JSONSL_SPECIALf_FLOAT) {
317 0 0         INVOKE_ERROR(INVALID_NUMBER);
318             }
319 9           state->special_flags |= JSONSL_SPECIALf_FLOAT;
320 9           STATE_NUM_LAST = '.';
321 9           goto GT_NEXT;
322              
323             case 'e':
324             case 'E':
325 9 50         if (state->special_flags & JSONSL_SPECIALf_EXPONENT) {
326 0 0         INVOKE_ERROR(INVALID_NUMBER);
327             }
328 9           state->special_flags |= JSONSL_SPECIALf_EXPONENT;
329 9           STATE_NUM_LAST = 'e';
330 9           goto GT_NEXT;
331              
332             case '-':
333             case '+':
334 4 50         if (STATE_NUM_LAST != 'e') {
335 0 0         INVOKE_ERROR(INVALID_NUMBER);
336             }
337 4           STATE_NUM_LAST = '-';
338 4           goto GT_NEXT;
339              
340             default:
341 31 50         if (is_special_end(CUR_CHAR)) {
342 31           goto GT_SPECIAL_POP;
343             }
344 0 0         INVOKE_ERROR(INVALID_NUMBER);
345             break;
346             }
347             }
348             /* else if (!NUMERIC) */
349 31 100         if (!is_special_end(CUR_CHAR)) {
350 24           STATE_SPECIAL_LENGTH++;
351              
352             /* Verify TRUE, FALSE, NULL */
353 24 100         if (state->special_flags == JSONSL_SPECIALf_TRUE) {
354 6 50         VERIFY_SPECIAL("true");
    0          
355 18 100         } else if (state->special_flags == JSONSL_SPECIALf_FALSE) {
356 8 50         VERIFY_SPECIAL("false");
    0          
357 10 50         } else if (state->special_flags == JSONSL_SPECIALf_NULL) {
358 10 100         VERIFY_SPECIAL("null");
    0          
359             }
360             INCR_METRIC(SPECIAL_FASTPATH);
361 23           goto GT_NEXT;
362             }
363              
364             GT_SPECIAL_POP:
365 38 100         if (IS_NORMAL_NUMBER) {
    100          
366             /* Nothing */
367 21 50         } else if (state->special_flags == JSONSL_SPECIALf_ZERO ||
    50          
368 21           state->special_flags == (JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED)) {
369             /* 0 is unsigned! */
370 0           state->special_flags = JSONSL_SPECIALf_UNSIGNED;
371 21 50         } else if (state->special_flags == JSONSL_SPECIALf_DASH) {
372             /* Still in dash! */
373 0 0         INVOKE_ERROR(INVALID_NUMBER);
374 21 100         } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
375             /* Check that we're not at the end of a token */
376 14 100         if (STATE_NUM_LAST != '1') {
377 2 0         INVOKE_ERROR(INVALID_NUMBER);
378             }
379 7 100         } else if (state->special_flags == JSONSL_SPECIALf_TRUE) {
380 2 50         if (STATE_SPECIAL_LENGTH != 4) {
381 0 0         INVOKE_ERROR(SPECIAL_INCOMPLETE);
382             }
383 2           state->nelem = 1;
384 5 100         } else if (state->special_flags == JSONSL_SPECIALf_FALSE) {
385 2 50         if (STATE_SPECIAL_LENGTH != 5) {
386 0 0         INVOKE_ERROR(SPECIAL_INCOMPLETE);
387             }
388 3 50         } else if (state->special_flags == JSONSL_SPECIALf_NULL) {
389 3 50         if (STATE_SPECIAL_LENGTH != 4) {
390 0 0         INVOKE_ERROR(SPECIAL_INCOMPLETE);
391             }
392             }
393 36 50         SPECIAL_POP;
    50          
    50          
    50          
    0          
    50          
394 36           jsn->expecting = ',';
395 36 100         if (is_allowed_whitespace(CUR_CHAR)) {
396 2           goto GT_NEXT;
397             }
398             /**
399             * This works because we have a non-whitespace token
400             * which is not a special token. If this is a structural
401             * character then it will be gracefully handled by the
402             * switch statement. Otherwise it will default to the 'special'
403             * state again,
404             */
405 34           goto GT_STRUCTURAL_TOKEN;
406 5750 100         } else if (is_allowed_whitespace(CUR_CHAR)) {
407             INCR_METRIC(ALLOWED_WHITESPACE);
408             /* So we're not special. Harmless insignificant whitespace
409             * passthrough
410             */
411 247           goto GT_NEXT;
412 5503 100         } else if (extract_special(CUR_CHAR)) {
413             /* not a string, whitespace, or structural token. must be special */
414 42           goto GT_SPECIAL_BEGIN;
415             }
416              
417             INCR_GENERIC(CUR_CHAR);
418              
419 5461 100         if (CUR_CHAR == '"') {
420             GT_QUOTE:
421 2229           jsn->can_insert = 0;
422 2229           switch (state_type) {
423              
424             /* the end of a string or hash key */
425             case JSONSL_T_STRING:
426 31 50         CALLBACK_AND_POP(STRING);
    50          
    50          
    50          
    0          
    50          
427 31           goto GT_NEXT;
428             case JSONSL_T_HKEY:
429 1082 50         CALLBACK_AND_POP(HKEY);
    50          
    50          
    50          
    0          
    50          
430 1082           goto GT_NEXT;
431              
432             case JSONSL_T_OBJECT:
433 1107           state->nelem++;
434 1107 100         if ( (state->nelem-1) % 2 ) {
435             /* Odd, this must be a hash value */
436 24 50         if (jsn->tok_last != ':') {
437 0 0         INVOKE_ERROR(MISSING_TOKEN);
438             }
439 24           jsn->expecting = ','; /* Can't figure out what to expect next */
440 24           jsn->tok_last = 0;
441              
442 24 50         STACK_PUSH;
443 24           state->type = JSONSL_T_STRING;
444 24 50         DO_CALLBACK(STRING, PUSH);
    50          
    50          
    50          
    0          
    50          
445              
446             } else {
447             /* hash key */
448 1083 50         if (jsn->expecting != '"') {
449 0 0         INVOKE_ERROR(STRAY_TOKEN);
450             }
451 1083           jsn->tok_last = 0;
452 1083           jsn->expecting = ':';
453              
454 1083 100         STACK_PUSH;
455 1082           state->type = JSONSL_T_HKEY;
456 1082 50         DO_CALLBACK(HKEY, PUSH);
    50          
    50          
    50          
    0          
    50          
457             }
458 1106           goto GT_NEXT;
459              
460             case JSONSL_T_LIST:
461 9           state->nelem++;
462 9 50         STACK_PUSH;
463 9           state->type = JSONSL_T_STRING;
464 9           jsn->expecting = ',';
465 9           jsn->tok_last = 0;
466 9 50         DO_CALLBACK(STRING, PUSH);
    50          
    50          
    50          
    0          
    50          
467 9           goto GT_NEXT;
468              
469             case JSONSL_T_SPECIAL:
470 0 0         INVOKE_ERROR(STRAY_TOKEN);
471             break;
472              
473             default:
474 0 0         INVOKE_ERROR(STRING_OUTSIDE_CONTAINER);
475             break;
476             } /* switch(state->type) */
477 4345 50         } else if (CUR_CHAR == '\\') {
478             GT_ESCAPE:
479             INCR_METRIC(ESCAPES);
480             /* Escape */
481 13 50         if ( (state->type & JSONSL_Tf_STRINGY) == 0 ) {
482 0 0         INVOKE_ERROR(ESCAPE_OUTSIDE_STRING);
483             }
484 13           state->nescapes++;
485 13           jsn->in_escape = 1;
486 13           goto GT_NEXT;
487             } /* " or \ */
488              
489             GT_STRUCTURAL_TOKEN:
490 4379           switch (CUR_CHAR) {
491             case ':':
492             INCR_METRIC(STRUCTURAL_TOKEN);
493 1082 50         if (jsn->expecting != CUR_CHAR) {
494 0 0         INVOKE_ERROR(STRAY_TOKEN);
495             }
496 1082           jsn->tok_last = ':';
497 1082           jsn->can_insert = 1;
498 1082           jsn->expecting = '"';
499 1082           goto GT_NEXT;
500              
501             case ',':
502             INCR_METRIC(STRUCTURAL_TOKEN);
503             /**
504             * The comma is one of the more generic tokens.
505             * In the context of an OBJECT, the can_insert flag
506             * should never be set, and no other action is
507             * necessary.
508             */
509 29 50         if (jsn->expecting != CUR_CHAR) {
510             /* make this branch execute only when we haven't manually
511             * just placed the ',' in the expecting register.
512             */
513 0 0         INVOKE_ERROR(STRAY_TOKEN);
514             }
515              
516 29 100         if (state->type == JSONSL_T_OBJECT) {
517             /* end of hash value, expect a string as a hash key */
518 17           jsn->expecting = '"';
519             } else {
520 12           jsn->can_insert = 1;
521             }
522              
523 29           jsn->tok_last = ',';
524 29           jsn->expecting = '"';
525 29           goto GT_NEXT;
526              
527             /* new list or object */
528             /* hashes are more common */
529             case '{':
530             case '[':
531             INCR_METRIC(STRUCTURAL_TOKEN);
532 2152 50         if (!jsn->can_insert) {
533 0 0         INVOKE_ERROR(CANT_INSERT);
534             }
535              
536 2152 100         ENSURE_HVAL;
    50          
    0          
537 2152           state->nelem++;
538              
539 2152 100         STACK_PUSH;
540             /* because the constants match the opening delimiters, we can do this: */
541 2151           state->type = CUR_CHAR;
542 2151           state->nelem = 0;
543 2151           jsn->can_insert = 1;
544 2151 100         if (CUR_CHAR == '{') {
545             /* If we're a hash, we expect a key first, which is quouted */
546 1066           jsn->expecting = '"';
547             }
548 2151 100         if (CUR_CHAR == JSONSL_T_OBJECT) {
549 1066 50         DO_CALLBACK(OBJECT, PUSH);
    50          
    50          
    100          
    50          
    50          
550             } else {
551 1085 50         DO_CALLBACK(LIST, PUSH);
    50          
    50          
    100          
    50          
    50          
552             }
553 2151           jsn->tok_last = 0;
554 2151           goto GT_NEXT;
555              
556             /* closing of list or object */
557             case '}':
558             case ']':
559             INCR_METRIC(STRUCTURAL_TOKEN);
560 1111 50         if (jsn->tok_last == ',' && jsn->options.allow_trailing_comma == 0) {
    0          
561 0 0         INVOKE_ERROR(TRAILING_COMMA);
562             }
563              
564 1111           jsn->can_insert = 0;
565 1111           jsn->level--;
566 1111           jsn->expecting = ',';
567 1111           jsn->tok_last = 0;
568 1111 100         if (CUR_CHAR == ']') {
569 572 50         if (state->type != '[') {
570 0 0         INVOKE_ERROR(BRACKET_MISMATCH);
571             }
572 572 50         DO_CALLBACK(LIST, POP);
    50          
    50          
    50          
    0          
    50          
573             } else {
574 539 50         if (state->type != '{') {
575 0 0         INVOKE_ERROR(BRACKET_MISMATCH);
576 539 50         } else if (state->nelem && state->nelem % 2 != 0) {
    50          
577 0 0         INVOKE_ERROR(VALUE_EXPECTED);
578             }
579 539 50         DO_CALLBACK(OBJECT, POP);
    50          
    50          
    50          
    0          
    50          
580             }
581 1111           state = jsn->stack + jsn->level;
582 1111           state->pos_cur = jsn->pos;
583 1111           goto GT_NEXT;
584              
585             default:
586             GT_SPECIAL_BEGIN:
587             /**
588             * Not a string, not a structural token, and not benign whitespace.
589             * Technically we should iterate over the character always, but since
590             * we are not doing full numerical/value decoding anyway (but only hinting),
591             * we only check upon entry.
592             */
593 47 50         if (state->type != JSONSL_T_SPECIAL) {
594 47           int special_flags = extract_special(CUR_CHAR);
595 47 100         if (!special_flags) {
596             /**
597             * Try to do some heuristics here anyway to figure out what kind of
598             * error this is. The 'special' case is a fallback scenario anyway.
599             */
600 5 50         if (CUR_CHAR == '\0') {
601 0 0         INVOKE_ERROR(FOUND_NULL_BYTE);
602 5 100         } else if (CUR_CHAR < 0x20) {
603 1 0         INVOKE_ERROR(WEIRD_WHITESPACE);
604             } else {
605 4 0         INVOKE_ERROR(SPECIAL_EXPECTED);
606             }
607             }
608 42 100         ENSURE_HVAL;
    50          
    0          
609 42           state->nelem++;
610 42 50         if (!jsn->can_insert) {
611 0 0         INVOKE_ERROR(CANT_INSERT);
612             }
613 42 50         STACK_PUSH;
614 42           state->type = JSONSL_T_SPECIAL;
615 42           state->special_flags = special_flags;
616 42           STATE_SPECIAL_LENGTH = 1;
617              
618 42 100         if (special_flags == JSONSL_SPECIALf_UNSIGNED) {
619 20           state->nelem = CUR_CHAR - 0x30;
620 20           STATE_NUM_LAST = '1';
621             } else {
622 22           STATE_NUM_LAST = '-';
623 22           state->nelem = 0;
624             }
625 42 50         DO_CALLBACK(SPECIAL, PUSH);
    50          
    50          
    50          
    0          
    50          
626             }
627 42           goto GT_NEXT;
628             }
629              
630             GT_NEXT:
631 7519           continue;
632             }
633             }
634              
635             JSONSL_API
636 15           const char* jsonsl_strerror(jsonsl_error_t err)
637             {
638 15 50         if (err == JSONSL_ERROR_SUCCESS) {
639 0           return "SUCCESS";
640             }
641             #define X(t) \
642             if (err == JSONSL_ERROR_##t) \
643             return #t;
644 15 50         JSONSL_XERR;
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    100          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
645             #undef X
646 0           return "";
647             }
648              
649             JSONSL_API
650 0           const char *jsonsl_strtype(jsonsl_type_t type)
651             {
652             #define X(o,c) \
653             if (type == JSONSL_T_##o) \
654             return #o;
655 0 0         JSONSL_XTYPE
    0          
    0          
    0          
    0          
    0          
656             #undef X
657 0           return "UNKNOWN TYPE";
658              
659             }
660              
661             /*
662             *
663             * JPR/JSONPointer functions
664             *
665             *
666             */
667             #ifndef JSONSL_NO_JPR
668             static
669             jsonsl_jpr_type_t
670 5           populate_component(char *in,
671             struct jsonsl_jpr_component_st *component,
672             char **next,
673             jsonsl_error_t *errp)
674             {
675             unsigned long pctval;
676 5           char *c = NULL, *outp = NULL, *end = NULL;
677             size_t input_len;
678 5           jsonsl_jpr_type_t ret = JSONSL_PATH_NONE;
679              
680 5 50         if (*next == NULL || *(*next) == '\0') {
    50          
681 0           return JSONSL_PATH_NONE;
682             }
683              
684             /* Replace the next / with a NULL */
685 5           *next = strstr(in, "/");
686 5 100         if (*next != NULL) {
687 1           *(*next) = '\0'; /* drop the forward slash */
688 1           input_len = *next - in;
689 1           end = *next;
690 1           *next += 1; /* next character after the '/' */
691             } else {
692 4           input_len = strlen(in);
693 4           end = in + input_len + 1;
694             }
695              
696 5           component->pstr = in;
697              
698             /* Check for special components of interest */
699 5 100         if (*in == JSONSL_PATH_WILDCARD_CHAR && input_len == 1) {
    50          
700             /* Lone wildcard */
701 4           ret = JSONSL_PATH_WILDCARD;
702 4           goto GT_RET;
703 1 50         } else if (isdigit(*in)) {
704             /* ASCII Numeric */
705             char *endptr;
706 0           component->idx = strtoul(in, &endptr, 10);
707 0 0         if (endptr && *endptr == '\0') {
    0          
708 0           ret = JSONSL_PATH_NUMERIC;
709 0           goto GT_RET;
710             }
711             }
712              
713             /* Default, it's a string */
714 1           ret = JSONSL_PATH_STRING;
715 9 100         for (c = outp = in; c < end; c++, outp++) {
716             char origc;
717 8 50         if (*c != '%') {
718 8           goto GT_ASSIGN;
719             }
720             /*
721             * c = { [+0] = '%', [+1] = 'b', [+2] = 'e', [+3] = '\0' }
722             */
723              
724             /* Need %XX */
725 0 0         if (c+2 >= end) {
726 0           *errp = JSONSL_ERROR_PERCENT_BADHEX;
727 0           return JSONSL_PATH_INVALID;
728             }
729 0 0         if (! (isxdigit(*(c+1)) && isxdigit(*(c+2))) ) {
    0          
730 0           *errp = JSONSL_ERROR_PERCENT_BADHEX;
731 0           return JSONSL_PATH_INVALID;
732             }
733              
734             /* Temporarily null-terminate the characters */
735 0           origc = *(c+3);
736 0           *(c+3) = '\0';
737 0           pctval = strtoul(c+1, NULL, 16);
738 0           *(c+3) = origc;
739              
740 0           *outp = (char) pctval;
741 0           c += 2;
742 0           continue;
743              
744             GT_ASSIGN:
745 8           *outp = *c;
746             }
747             /* Null-terminate the string */
748 1 50         for (; outp < c; outp++) {
749 0           *outp = '\0';
750             }
751              
752             GT_RET:
753 5           component->ptype = ret;
754 5 100         if (ret != JSONSL_PATH_WILDCARD) {
755 1           component->len = strlen(component->pstr);
756             }
757 5           return ret;
758             }
759              
760             JSONSL_API
761             jsonsl_jpr_t
762 4           jsonsl_jpr_new(const char *path, jsonsl_error_t *errp)
763             {
764 4           char *my_copy = NULL;
765             int count, curidx;
766 4           struct jsonsl_jpr_st *ret = NULL;
767 4           struct jsonsl_jpr_component_st *components = NULL;
768             size_t origlen;
769             jsonsl_error_t errstacked;
770              
771             #define JPR_BAIL(err) *errp = err; goto GT_ERROR;
772              
773 4 50         if (errp == NULL) {
774 0           errp = &errstacked;
775             }
776              
777 4 50         if (path == NULL || *path != '/') {
    50          
778 0           JPR_BAIL(JSONSL_ERROR_JPR_NOROOT);
779             return NULL;
780             }
781              
782 4           count = 1;
783 4           path++;
784             {
785 4           const char *c = path;
786 16 100         for (; *c; c++) {
787 12 100         if (*c == '/') {
788 1           count++;
789 1 50         if (*(c+1) == '/') {
790 0           JPR_BAIL(JSONSL_ERROR_JPR_DUPSLASH);
791             }
792             }
793             }
794             }
795 4 50         if(*path) {
796 4           count++;
797             }
798              
799 4           components = (struct jsonsl_jpr_component_st *)
800 4           malloc(sizeof(*components) * count);
801 4 50         if (!components) {
802 0           JPR_BAIL(JSONSL_ERROR_ENOMEM);
803             }
804              
805 4           my_copy = (char *)malloc(strlen(path) + 1);
806 4 50         if (!my_copy) {
807 0           JPR_BAIL(JSONSL_ERROR_ENOMEM);
808             }
809              
810 4           strcpy(my_copy, path);
811              
812 4           components[0].ptype = JSONSL_PATH_ROOT;
813              
814 4 50         if (*my_copy) {
815 4           char *cur = my_copy;
816 4           int pathret = JSONSL_PATH_STRING;
817 4           curidx = 1;
818 9 50         while (pathret > 0 && curidx < count) {
    100          
819 5           pathret = populate_component(cur, components + curidx, &cur, errp);
820 5 50         if (pathret > 0) {
821 5           curidx++;
822             } else {
823 0           break;
824             }
825             }
826              
827 4 50         if (pathret == JSONSL_PATH_INVALID) {
828 4           JPR_BAIL(JSONSL_ERROR_JPR_BADPATH);
829             }
830             } else {
831 0           curidx = 1;
832             }
833              
834 4           path--; /*revert path to leading '/' */
835 4           origlen = strlen(path) + 1;
836 4           ret = (struct jsonsl_jpr_st *)malloc(sizeof(*ret));
837 4 50         if (!ret) {
838 0           JPR_BAIL(JSONSL_ERROR_ENOMEM);
839             }
840 4           ret->orig = (char *)malloc(origlen);
841 4 50         if (!ret->orig) {
842 0           JPR_BAIL(JSONSL_ERROR_ENOMEM);
843             }
844 4           ret->components = components;
845 4           ret->ncomponents = curidx;
846 4           ret->basestr = my_copy;
847 4           ret->norig = origlen-1;
848 4           strcpy(ret->orig, path);
849              
850 4           return ret;
851              
852             GT_ERROR:
853 0           free(my_copy);
854 0           free(components);
855 0 0         if (ret) {
856 0           free(ret->orig);
857             }
858 0           free(ret);
859 4           return NULL;
860             #undef JPR_BAIL
861             }
862              
863 4           void jsonsl_jpr_destroy(jsonsl_jpr_t jpr)
864             {
865 4           free(jpr->components);
866 4           free(jpr->basestr);
867 4           free(jpr->orig);
868 4           free(jpr);
869 4           }
870              
871             JSONSL_API
872             jsonsl_jpr_match_t
873 18           jsonsl_jpr_match(jsonsl_jpr_t jpr,
874             unsigned int parent_type,
875             unsigned int parent_level,
876             const char *key,
877             size_t nkey)
878             {
879             /* find our current component. This is the child level */
880             int cmpret;
881             struct jsonsl_jpr_component_st *p_component;
882 18           p_component = jpr->components + parent_level;
883              
884 18 50         if (parent_level >= jpr->ncomponents) {
885 0           return JSONSL_MATCH_NOMATCH;
886             }
887              
888             /* Lone query for 'root' element. Always matches */
889 18 100         if (parent_level == 0) {
890 6 50         if (jpr->ncomponents == 1) {
891 0           return JSONSL_MATCH_COMPLETE;
892             } else {
893 6           return JSONSL_MATCH_POSSIBLE;
894             }
895             }
896              
897             /* Wildcard, always matches */
898 12 100         if (p_component->ptype == JSONSL_PATH_WILDCARD) {
899 9 100         if (parent_level == jpr->ncomponents-1) {
900 6           return JSONSL_MATCH_COMPLETE;
901             } else {
902 3           return JSONSL_MATCH_POSSIBLE;
903             }
904             }
905              
906             /* Check numeric array index. This gets its special block so we can avoid
907             * string comparisons */
908 3 50         if (p_component->ptype == JSONSL_PATH_NUMERIC) {
909 0 0         if (parent_type == JSONSL_T_LIST) {
910 0 0         if (p_component->idx != nkey) {
911             /* Wrong index */
912 0           return JSONSL_MATCH_NOMATCH;
913             } else {
914 0 0         if (parent_level == jpr->ncomponents-1) {
915             /* This is the last element of the path */
916 0           return JSONSL_MATCH_COMPLETE;
917             } else {
918             /* Intermediate element */
919 0           return JSONSL_MATCH_POSSIBLE;
920             }
921             }
922 0 0         } else if (p_component->is_arridx) {
923             /* Numeric and an array index (set explicitly by user). But not
924             * a list for a parent */
925 0           return JSONSL_MATCH_TYPE_MISMATCH;
926             }
927 3 50         } else if (parent_type == JSONSL_T_LIST) {
928 0           return JSONSL_MATCH_TYPE_MISMATCH;
929             }
930              
931             /* Check lengths */
932 3 100         if (p_component->len != nkey) {
933 1           return JSONSL_MATCH_NOMATCH;
934             }
935              
936             /* Check string comparison */
937 2           cmpret = strncmp(p_component->pstr, key, nkey);
938 2 50         if (cmpret == 0) {
939 2 50         if (parent_level == jpr->ncomponents-1) {
940 2           return JSONSL_MATCH_COMPLETE;
941             } else {
942 0           return JSONSL_MATCH_POSSIBLE;
943             }
944             }
945              
946 0           return JSONSL_MATCH_NOMATCH;
947             }
948              
949             JSONSL_API
950 4           void jsonsl_jpr_match_state_init(jsonsl_t jsn,
951             jsonsl_jpr_t *jprs,
952             size_t njprs)
953             {
954             size_t ii, *firstjmp;
955 4 50         if (njprs == 0) {
956 0           return;
957             }
958 4           jsn->jprs = (jsonsl_jpr_t *)malloc(sizeof(jsonsl_jpr_t) * njprs);
959 4           jsn->jpr_count = njprs;
960 4           jsn->jpr_root = (size_t*)calloc(1, sizeof(size_t) * njprs * jsn->levels_max);
961 4           memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs);
962             /* Set the initial jump table values */
963              
964 4           firstjmp = jsn->jpr_root;
965 8 100         for (ii = 0; ii < njprs; ii++) {
966 4           firstjmp[ii] = ii+1;
967             }
968             }
969              
970             JSONSL_API
971 24           void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn)
972             {
973 24 100         if (jsn->jpr_count == 0) {
974 20           return;
975             }
976              
977 4           free(jsn->jpr_root);
978 4           free(jsn->jprs);
979 4           jsn->jprs = NULL;
980 4           jsn->jpr_root = NULL;
981 4           jsn->jpr_count = 0;
982             }
983              
984             /**
985             * This function should be called exactly once on each element...
986             * This should also be called in recursive order, since we rely
987             * on the parent having been initalized for a match.
988             *
989             * Since the parent is checked for a match as well, we maintain a 'serial' counter.
990             * Whenever we traverse an element, we expect the serial to be the same as a global
991             * integer. If they do not match, we re-initialize the context, and set the serial.
992             *
993             * This ensures a type of consistency without having a proactive reset by the
994             * main lexer itself.
995             *
996             */
997             JSONSL_API
998 72           jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn,
999             struct jsonsl_state_st *state,
1000             const char *key,
1001             size_t nkey,
1002             jsonsl_jpr_match_t *out)
1003             {
1004             struct jsonsl_state_st *parent_state;
1005 72           jsonsl_jpr_t ret = NULL;
1006              
1007             /* Jump and JPR tables for our own state and the parent state */
1008             size_t *jmptable, *pjmptable;
1009             size_t jmp_cur, ii, ourjmpidx;
1010              
1011 72 100         if (!jsn->jpr_root) {
1012 54           *out = JSONSL_MATCH_NOMATCH;
1013 54           return NULL;
1014             }
1015              
1016 18           pjmptable = jsn->jpr_root + (jsn->jpr_count * (state->level-1));
1017 18           jmptable = pjmptable + jsn->jpr_count;
1018              
1019             /* If the parent cannot match, then invalidate it */
1020 18 50         if (*pjmptable == 0) {
1021 0           *jmptable = 0;
1022 0           *out = JSONSL_MATCH_NOMATCH;
1023 0           return NULL;
1024             }
1025              
1026 18           parent_state = jsn->stack + state->level - 1;
1027              
1028 18 100         if (parent_state->type == JSONSL_T_LIST) {
1029 5           nkey = (size_t) parent_state->nelem;
1030             }
1031              
1032 18           *jmptable = 0;
1033 18           ourjmpidx = 0;
1034 18           memset(jmptable, 0, sizeof(int) * jsn->jpr_count);
1035              
1036 28 100         for (ii = 0; ii < jsn->jpr_count; ii++) {
1037 18           jmp_cur = pjmptable[ii];
1038 18 50         if (jmp_cur) {
1039 18           jsonsl_jpr_t jpr = jsn->jprs[jmp_cur-1];
1040 18           *out = jsonsl_jpr_match(jpr,
1041             parent_state->type,
1042             parent_state->level,
1043             key, nkey);
1044 18 100         if (*out == JSONSL_MATCH_COMPLETE) {
1045 8           ret = jpr;
1046 8           *jmptable = 0;
1047 8           return ret;
1048 10 100         } else if (*out == JSONSL_MATCH_POSSIBLE) {
1049 9           jmptable[ourjmpidx] = ii+1;
1050 10           ourjmpidx++;
1051             }
1052             } else {
1053 0           break;
1054             }
1055             }
1056 10 100         if (!*jmptable) {
1057 1           *out = JSONSL_MATCH_NOMATCH;
1058             }
1059 10           return NULL;
1060             }
1061              
1062             JSONSL_API
1063 0           const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match)
1064             {
1065             #define X(T,v) \
1066             if ( match == JSONSL_MATCH_##T ) \
1067             return #T;
1068 0 0         JSONSL_XMATCH
    0          
    0          
    0          
1069             #undef X
1070 0           return "";
1071             }
1072              
1073             #endif /* JSONSL_WITH_JPR */
1074              
1075             /**
1076             * Utility function to convert escape sequences
1077             */
1078             JSONSL_API
1079 14           size_t jsonsl_util_unescape_ex(const char *in,
1080             char *out,
1081             size_t len,
1082             const int toEscape[128],
1083             unsigned *oflags,
1084             jsonsl_error_t *err,
1085             const char **errat)
1086             {
1087 14           const unsigned char *c = (const unsigned char*)in;
1088 14           int in_escape = 0;
1089 14           size_t origlen = len;
1090             /* difference between the length of the input buffer and the output buffer */
1091 14           size_t ndiff = 0;
1092 14 50         if (oflags) {
1093 14           *oflags = 0;
1094             }
1095             #define UNESCAPE_BAIL(e,offset) \
1096             *err = JSONSL_ERROR_##e; \
1097             if (errat) { \
1098             *errat = (const char*)(c+ (ptrdiff_t)(offset)); \
1099             } \
1100             return 0;
1101              
1102 106 100         for (; len; len--, c++, out++) {
1103             unsigned int uesc_val[2];
1104 93 100         if (in_escape) {
1105             /* inside a previously ignored escape. Ignore */
1106 2           in_escape = 0;
1107 2           goto GT_ASSIGN;
1108             }
1109              
1110 91 100         if (*c != '\\') {
1111             /* Not an escape, so we don't care about this */
1112 75           goto GT_ASSIGN;
1113             }
1114              
1115 16 50         if (len < 2) {
1116 1 0         UNESCAPE_BAIL(ESCAPE_INVALID, 0);
1117             }
1118 16 100         if (!is_allowed_escape(c[1])) {
1119 1 50         UNESCAPE_BAIL(ESCAPE_INVALID, 1)
1120             }
1121 15 100         if ((toEscape[(unsigned char)c[1] & 0x7f] == 0 &&
    50          
1122 2 50         c[1] != '\\' && c[1] != '"')) {
1123             /* if we don't want to unescape this string, just continue with
1124             * the escape flag set
1125             */
1126 2           in_escape = 1;
1127 2           goto GT_ASSIGN;
1128             }
1129              
1130 13 100         if (c[1] != 'u') {
1131             /* simple skip-and-replace using pre-defined maps.
1132             * TODO: should the maps actually reflect the desired
1133             * replacement character in toEscape?
1134             */
1135 7           char esctmp = get_escape_equiv(c[1]);
1136 7 100         if (esctmp) {
1137             /* Check if there is a corresponding replacement */
1138 5           *out = esctmp;
1139             } else {
1140             /* Just gobble up the 'reverse-solidus' */
1141 2           *out = c[1];
1142             }
1143 7           len--;
1144 7           ndiff++;
1145 7           c++;
1146             /* do not assign, just continue */
1147 13           continue;
1148             }
1149              
1150             /* next == 'u' */
1151 6 50         if (len < 6) {
1152             /* Need at least six characters:
1153             * { [0] = '\\', [1] = 'u', [2] = 'f', [3] = 'f', [4] = 'f', [5] = 'f' }
1154             */
1155 0 0         UNESCAPE_BAIL(UESCAPE_TOOSHORT, -1);
1156             }
1157              
1158 6 50         if (sscanf((const char*)(c+2), "%02x%02x", uesc_val, uesc_val+1) != 2) {
1159             /* We treat the sequence as two octets */
1160 0 0         UNESCAPE_BAIL(UESCAPE_TOOSHORT, -1);
1161             }
1162              
1163             /* By now, we gobble up all the six bytes (current implied + 5 next
1164             * characters), and have at least four missing bytes from the output
1165             * buffer.
1166             */
1167 6           len -= 5;
1168 6           c += 5;
1169              
1170 6           ndiff += 4;
1171 6 100         if (uesc_val[0] == 0) {
1172             /* only one byte is extracted from the two
1173             * possible octets. Increment the diff counter by one.
1174             */
1175 5           *out = uesc_val[1];
1176 5 50         if (oflags && *(unsigned char*)out > 0x7f) {
    50          
1177 0           *oflags |= JSONSL_SPECIALf_NONASCII;
1178             }
1179 5           ndiff++;
1180             } else {
1181 1           *(out++) = uesc_val[0];
1182 1           *out = uesc_val[1];
1183 1 50         if (oflags && (uesc_val[0] > 0x7f || uesc_val[1] > 0x7f)) {
    50          
    0          
1184 1           *oflags |= JSONSL_SPECIALf_NONASCII;
1185             }
1186             }
1187 6           continue;
1188              
1189             /* Only reached by previous branches */
1190             GT_ASSIGN:
1191 79           *out = *c;
1192             }
1193 13           *err = JSONSL_ERROR_SUCCESS;
1194 13           return origlen - ndiff;
1195             }
1196              
1197             /**
1198             * Character Table definitions.
1199             * These were all generated via srcutil/genchartables.pl
1200             */
1201              
1202             /**
1203             * This table contains the beginnings of non-string
1204             * allowable (bareword) values.
1205             */
1206             static unsigned short Special_Table[0x100] = {
1207             /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1208             /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2c */
1209             /* 0x2d */ JSONSL_SPECIALf_DASH /* <-> */, /* 0x2d */
1210             /* 0x2e */ 0,0, /* 0x2f */
1211             /* 0x30 */ JSONSL_SPECIALf_ZERO /* <0> */, /* 0x30 */
1212             /* 0x31 */ JSONSL_SPECIALf_UNSIGNED /* <1> */, /* 0x31 */
1213             /* 0x32 */ JSONSL_SPECIALf_UNSIGNED /* <2> */, /* 0x32 */
1214             /* 0x33 */ JSONSL_SPECIALf_UNSIGNED /* <3> */, /* 0x33 */
1215             /* 0x34 */ JSONSL_SPECIALf_UNSIGNED /* <4> */, /* 0x34 */
1216             /* 0x35 */ JSONSL_SPECIALf_UNSIGNED /* <5> */, /* 0x35 */
1217             /* 0x36 */ JSONSL_SPECIALf_UNSIGNED /* <6> */, /* 0x36 */
1218             /* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */
1219             /* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */
1220             /* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */
1221             /* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x59 */
1222             /* 0x5a */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */
1223             /* 0x66 */ JSONSL_SPECIALf_FALSE /* */, /* 0x66 */
1224             /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
1225             /* 0x6e */ JSONSL_SPECIALf_NULL /* */, /* 0x6e */
1226             /* 0x6f */ 0,0,0,0,0, /* 0x73 */
1227             /* 0x74 */ JSONSL_SPECIALf_TRUE /* */, /* 0x74 */
1228             /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */
1229             /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */
1230             /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */
1231             /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */
1232             /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0, /* 0xfe */
1233             };
1234              
1235             /**
1236             * Contains characters which signal the termination of any of the 'special' bareword
1237             * values.
1238             */
1239             static int Special_Endings[0x100] = {
1240             /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */
1241             /* 0x09 */ 1 /* */, /* 0x09 */
1242             /* 0x0a */ 1 /* */, /* 0x0a */
1243             /* 0x0b */ 0,0, /* 0x0c */
1244             /* 0x0d */ 1 /* */, /* 0x0d */
1245             /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1246             /* 0x20 */ 1 /* */, /* 0x20 */
1247             /* 0x21 */ 0, /* 0x21 */
1248             /* 0x22 */ 1 /* " */, /* 0x22 */
1249             /* 0x23 */ 0,0,0,0,0,0,0,0,0, /* 0x2b */
1250             /* 0x2c */ 1 /* , */, /* 0x2c */
1251             /* 0x2d */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x39 */
1252             /* 0x3a */ 1 /* : */, /* 0x3a */
1253             /* 0x3b */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5a */
1254             /* 0x5b */ 1 /* [ */, /* 0x5b */
1255             /* 0x5c */ 1 /* \ */, /* 0x5c */
1256             /* 0x5d */ 1 /* ] */, /* 0x5d */
1257             /* 0x5e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7a */
1258             /* 0x7b */ 1 /* { */, /* 0x7b */
1259             /* 0x7c */ 0, /* 0x7c */
1260             /* 0x7d */ 1 /* } */, /* 0x7d */
1261             /* 0x7e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9d */
1262             /* 0x9e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbd */
1263             /* 0xbe */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdd */
1264             /* 0xde */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfd */
1265             /* 0xfe */ 0 /* 0xfe */
1266             };
1267              
1268             /**
1269             * This table contains entries for the allowed whitespace as per RFC 4627
1270             */
1271             static int Allowed_Whitespace[0x100] = {
1272             /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */
1273             /* 0x09 */ 1 /* */, /* 0x09 */
1274             /* 0x0a */ 1 /* */, /* 0x0a */
1275             /* 0x0b */ 0,0, /* 0x0c */
1276             /* 0x0d */ 1 /* */, /* 0x0d */
1277             /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1278             /* 0x20 */ 1 /* */, /* 0x20 */
1279             /* 0x21 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 */
1280             /* 0x41 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 */
1281             /* 0x61 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 */
1282             /* 0x81 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0 */
1283             /* 0xa1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xc0 */
1284             /* 0xc1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xe0 */
1285             /* 0xe1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xfe */
1286             };
1287              
1288             /**
1289             * Allowable two-character 'common' escapes:
1290             */
1291             static int Allowed_Escapes[0x100] = {
1292             /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1293             /* 0x20 */ 0,0, /* 0x21 */
1294             /* 0x22 */ 1 /* <"> */, /* 0x22 */
1295             /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2e */
1296             /* 0x2f */ 1 /* */, /* 0x2f */
1297             /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f */
1298             /* 0x50 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */
1299             /* 0x5c */ 1 /* <\> */, /* 0x5c */
1300             /* 0x5d */ 0,0,0,0,0, /* 0x61 */
1301             /* 0x62 */ 1 /* */, /* 0x62 */
1302             /* 0x63 */ 0,0,0, /* 0x65 */
1303             /* 0x66 */ 1 /* */, /* 0x66 */
1304             /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
1305             /* 0x6e */ 1 /* */, /* 0x6e */
1306             /* 0x6f */ 0,0,0, /* 0x71 */
1307             /* 0x72 */ 1 /* */, /* 0x72 */
1308             /* 0x73 */ 0, /* 0x73 */
1309             /* 0x74 */ 1 /* */, /* 0x74 */
1310             /* 0x75 */ 1 /* */, /* 0x75 */
1311             /* 0x76 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x95 */
1312             /* 0x96 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb5 */
1313             /* 0xb6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd5 */
1314             /* 0xd6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf5 */
1315             /* 0xf6 */ 0,0,0,0,0,0,0,0,0, /* 0xfe */
1316             };
1317              
1318             /**
1319             * This table contains the _values_ for a given (single) escaped character.
1320             */
1321             static unsigned char Escape_Equivs[0x100] = {
1322             /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1323             /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3f */
1324             /* 0x40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5f */
1325             /* 0x60 */ 0,0, /* 0x61 */
1326             /* 0x62 */ 8 /* */, /* 0x62 */
1327             /* 0x63 */ 0,0,0, /* 0x65 */
1328             /* 0x66 */ 12 /* */, /* 0x66 */
1329             /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
1330             /* 0x6e */ 10 /* */, /* 0x6e */
1331             /* 0x6f */ 0,0,0, /* 0x71 */
1332             /* 0x72 */ 13 /* */, /* 0x72 */
1333             /* 0x73 */ 0, /* 0x73 */
1334             /* 0x74 */ 9 /* */, /* 0x74 */
1335             /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */
1336             /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */
1337             /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */
1338             /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */
1339             /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0 /* 0xfe */
1340             };
1341              
1342             /* Definitions of above-declared static functions */
1343 7           static char get_escape_equiv(unsigned c) {
1344 7           return Escape_Equivs[c & 0xff];
1345             }
1346 5550           static unsigned extract_special(unsigned c) {
1347 5550           return Special_Table[c & 0xff];
1348             }
1349 62           static int is_special_end(unsigned c) {
1350 62           return Special_Endings[c & 0xff];
1351             }
1352 5786           static int is_allowed_whitespace(unsigned c) {
1353 5786 100         return c == ' ' || Allowed_Whitespace[c & 0xff];
    100          
1354             }
1355 29           static int is_allowed_escape(unsigned c) {
1356 29           return Allowed_Escapes[c & 0xff];
1357             }
1358              
1359             /* Clean up all our macros! */
1360             #undef INCR_METRIC
1361             #undef INCR_GENERIC
1362             #undef INCR_STRINGY_CATCH
1363             #undef CASE_DIGITS
1364             #undef INVOKE_ERROR
1365             #undef STACK_PUSH
1366             #undef STACK_POP_NOPOS
1367             #undef STACK_POP
1368             #undef CALLBACK_AND_POP_NOPOS
1369             #undef CALLBACK_AND_POP
1370             #undef SPECIAL_POP
1371             #undef CUR_CHAR
1372             #undef DO_CALLBACK
1373             #undef ENSURE_HVAL
1374             #undef VERIFY_SPECIAL
1375             #undef STATE_SPECIAL_LENGTH
1376             #undef IS_NORMAL_NUMBER
1377             #undef STATE_NUM_LAST