source: uKadecot/trunk/kadecot/jsonsl.c@ 165

Last change on this file since 165 was 108, checked in by coas-nagasima, 9 years ago

MIMEプロパティの変更

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