jsonsl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ # vim: et ts=2 sts=2 sw=2
2
+
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2018 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'rbconfig'
20
+ require 'mkmf'
21
+
22
+ def define(macro, value = nil)
23
+ $defs.push("-D #{[macro.upcase, Shellwords.shellescape(value)].compact.join('=')}")
24
+ end
25
+
26
+ $CFLAGS << ' -pedantic -Wall -Wextra -Werror '
27
+ if ENV['DEBUG_BUILD']
28
+ $CFLAGS.gsub!(/\W-Wp,-D_FORTIFY_SOURCE=\d+\W/, ' ')
29
+ $CFLAGS << ' -ggdb3 -O0 '
30
+ end
31
+ if ENV['FETCH_JSONSL']
32
+ require 'open-uri'
33
+ ['jsonsl.c', 'jsonsl.h'].each do |filename|
34
+ remote = open("https://github.com/mnunberg/jsonsl/raw/master/#{filename}")
35
+ File.write(File.join(__dir__, filename), remote.read)
36
+ end
37
+ Dir.chdir(__dir__) do
38
+ system('patch < jsonsl.h.patch')
39
+ end
40
+ sha1 = open('https://github.com/mnunberg/jsonsl').read[/commit-tease-sha.*?commit\/([a-f0-9]+)/m, 1]
41
+ File.write(File.join(__dir__, 'jsonsl.rev'), sha1)
42
+ end
43
+
44
+ define('JSONSL_REVISION', File.read(File.join(__dir__, 'jsonsl.rev')).strip.inspect)
45
+
46
+ create_header('jsonsl_config.h')
47
+ create_makefile('jsonsl_ext')
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012-2015 M. Nunberg, mnunberg@haskalah.org
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,1666 @@
1
+ /* Copyright (C) 2012-2015 Mark Nunberg.
2
+ *
3
+ * See included LICENSE file for license details.
4
+ */
5
+
6
+ #include "jsonsl.h"
7
+ #include <limits.h>
8
+ #include <ctype.h>
9
+
10
+ #ifdef JSONSL_USE_METRICS
11
+ #define XMETRICS \
12
+ X(STRINGY_INSIGNIFICANT) \
13
+ X(STRINGY_SLOWPATH) \
14
+ X(ALLOWED_WHITESPACE) \
15
+ X(QUOTE_FASTPATH) \
16
+ X(SPECIAL_FASTPATH) \
17
+ X(SPECIAL_WSPOP) \
18
+ X(SPECIAL_SLOWPATH) \
19
+ X(GENERIC) \
20
+ X(STRUCTURAL_TOKEN) \
21
+ X(SPECIAL_SWITCHFIRST) \
22
+ X(STRINGY_CATCH) \
23
+ X(NUMBER_FASTPATH) \
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
+ 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 int is_simple_char(unsigned);
98
+ static char get_escape_equiv(unsigned);
99
+
100
+ JSONSL_API
101
+ jsonsl_t jsonsl_new(int nlevels)
102
+ {
103
+ unsigned int ii;
104
+ struct jsonsl_st * jsn;
105
+
106
+ if (nlevels < 2) {
107
+ return NULL;
108
+ }
109
+
110
+ jsn = (struct jsonsl_st *)
111
+ calloc(1, sizeof (*jsn) +
112
+ ( (nlevels-1) * sizeof (struct jsonsl_state_st) )
113
+ );
114
+
115
+ jsn->levels_max = (unsigned int) nlevels;
116
+ jsn->max_callback_level = UINT_MAX;
117
+ jsonsl_reset(jsn);
118
+ for (ii = 0; ii < jsn->levels_max; ii++) {
119
+ jsn->stack[ii].level = ii;
120
+ }
121
+ return jsn;
122
+ }
123
+
124
+ JSONSL_API
125
+ void jsonsl_reset(jsonsl_t jsn)
126
+ {
127
+ jsn->tok_last = 0;
128
+ jsn->can_insert = 1;
129
+ jsn->pos = 0;
130
+ jsn->level = 0;
131
+ jsn->stopfl = 0;
132
+ jsn->in_escape = 0;
133
+ jsn->expecting = 0;
134
+ }
135
+
136
+ JSONSL_API
137
+ void jsonsl_destroy(jsonsl_t jsn)
138
+ {
139
+ if (jsn) {
140
+ free(jsn);
141
+ }
142
+ }
143
+
144
+
145
+ #define FASTPARSE_EXHAUSTED 1
146
+ #define FASTPARSE_BREAK 0
147
+
148
+ /*
149
+ * This function is meant to accelerate string parsing, reducing the main loop's
150
+ * check if we are indeed a string.
151
+ *
152
+ * @param jsn the parser
153
+ * @param[in,out] bytes_p A pointer to the current buffer (i.e. current position)
154
+ * @param[in,out] nbytes_p A pointer to the current size of the buffer
155
+ * @return true if all bytes have been exhausted (and thus the main loop can
156
+ * return), false if a special character was examined which requires greater
157
+ * examination.
158
+ */
159
+ static int
160
+ jsonsl__str_fastparse(jsonsl_t jsn,
161
+ const jsonsl_uchar_t **bytes_p, size_t *nbytes_p)
162
+ {
163
+ const jsonsl_uchar_t *bytes = *bytes_p;
164
+ const jsonsl_uchar_t *end;
165
+ for (end = bytes + *nbytes_p; bytes != end; bytes++) {
166
+ if (
167
+ #ifdef JSONSL_USE_WCHAR
168
+ *bytes >= 0x100 ||
169
+ #endif /* JSONSL_USE_WCHAR */
170
+ (is_simple_char(*bytes))) {
171
+ INCR_METRIC(TOTAL);
172
+ INCR_METRIC(STRINGY_INSIGNIFICANT);
173
+ } else {
174
+ /* Once we're done here, re-calculate the position variables */
175
+ jsn->pos += (bytes - *bytes_p);
176
+ *nbytes_p -= (bytes - *bytes_p);
177
+ *bytes_p = bytes;
178
+ return FASTPARSE_BREAK;
179
+ }
180
+ }
181
+
182
+ /* Once we're done here, re-calculate the position variables */
183
+ jsn->pos += (bytes - *bytes_p);
184
+ return FASTPARSE_EXHAUSTED;
185
+ }
186
+
187
+ /* Functions exactly like str_fastparse, except it also accepts a 'state'
188
+ * argument, since the number's value is updated in the state. */
189
+ static int
190
+ jsonsl__num_fastparse(jsonsl_t jsn,
191
+ const jsonsl_uchar_t **bytes_p, size_t *nbytes_p,
192
+ struct jsonsl_state_st *state)
193
+ {
194
+ int exhausted = 1;
195
+ size_t nbytes = *nbytes_p;
196
+ const jsonsl_uchar_t *bytes = *bytes_p;
197
+
198
+ for (; nbytes; nbytes--, bytes++) {
199
+ jsonsl_uchar_t c = *bytes;
200
+ if (isdigit(c)) {
201
+ INCR_METRIC(TOTAL);
202
+ INCR_METRIC(NUMBER_FASTPATH);
203
+ state->nelem = (state->nelem * 10) + (c - 0x30);
204
+ } else {
205
+ exhausted = 0;
206
+ break;
207
+ }
208
+ }
209
+ jsn->pos += (*nbytes_p - nbytes);
210
+ if (exhausted) {
211
+ return FASTPARSE_EXHAUSTED;
212
+ }
213
+ *nbytes_p = nbytes;
214
+ *bytes_p = bytes;
215
+ return FASTPARSE_BREAK;
216
+ }
217
+
218
+ JSONSL_API
219
+ void
220
+ jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
221
+ {
222
+
223
+ #define INVOKE_ERROR(eb) \
224
+ if (jsn->error_callback(jsn, JSONSL_ERROR_##eb, state, (char*)c)) { \
225
+ goto GT_AGAIN; \
226
+ } \
227
+ return;
228
+
229
+ #define STACK_PUSH \
230
+ if (jsn->level >= (levels_max-1)) { \
231
+ jsn->error_callback(jsn, JSONSL_ERROR_LEVELS_EXCEEDED, state, (char*)c); \
232
+ return; \
233
+ } \
234
+ state = jsn->stack + (++jsn->level); \
235
+ state->ignore_callback = jsn->stack[jsn->level-1].ignore_callback; \
236
+ state->pos_begin = jsn->pos;
237
+
238
+ #define STACK_POP_NOPOS \
239
+ state->pos_cur = jsn->pos; \
240
+ state = jsn->stack + (--jsn->level);
241
+
242
+
243
+ #define STACK_POP \
244
+ STACK_POP_NOPOS; \
245
+ state->pos_cur = jsn->pos;
246
+
247
+ #define CALLBACK_AND_POP_NOPOS(T) \
248
+ state->pos_cur = jsn->pos; \
249
+ DO_CALLBACK(T, POP); \
250
+ state->nescapes = 0; \
251
+ state = jsn->stack + (--jsn->level);
252
+
253
+ #define CALLBACK_AND_POP(T) \
254
+ CALLBACK_AND_POP_NOPOS(T); \
255
+ state->pos_cur = jsn->pos;
256
+
257
+ #define SPECIAL_POP \
258
+ CALLBACK_AND_POP(SPECIAL); \
259
+ jsn->expecting = 0; \
260
+ jsn->tok_last = 0; \
261
+
262
+ #define CUR_CHAR (*(jsonsl_uchar_t*)c)
263
+
264
+ #define DO_CALLBACK(T, action) \
265
+ if (jsn->call_##T && \
266
+ jsn->max_callback_level > state->level && \
267
+ state->ignore_callback == 0) { \
268
+ \
269
+ if (jsn->action_callback_##action) { \
270
+ jsn->action_callback_##action(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \
271
+ } else if (jsn->action_callback) { \
272
+ jsn->action_callback(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \
273
+ } \
274
+ if (jsn->stopfl) { return; } \
275
+ }
276
+
277
+ /**
278
+ * Verifies that we are able to insert the (non-string) item into a hash.
279
+ */
280
+ #define ENSURE_HVAL \
281
+ if (state->nelem % 2 == 0 && state->type == JSONSL_T_OBJECT) { \
282
+ INVOKE_ERROR(HKEY_EXPECTED); \
283
+ }
284
+
285
+ #define VERIFY_SPECIAL(lit) \
286
+ if (CUR_CHAR != (lit)[jsn->pos - state->pos_begin]) { \
287
+ INVOKE_ERROR(SPECIAL_EXPECTED); \
288
+ }
289
+
290
+ #define VERIFY_SPECIAL_CI(lit) \
291
+ if (tolower(CUR_CHAR) != (lit)[jsn->pos - state->pos_begin]) { \
292
+ INVOKE_ERROR(SPECIAL_EXPECTED); \
293
+ }
294
+
295
+ #define STATE_SPECIAL_LENGTH \
296
+ (state)->nescapes
297
+
298
+ #define IS_NORMAL_NUMBER \
299
+ ((state)->special_flags == JSONSL_SPECIALf_UNSIGNED || \
300
+ (state)->special_flags == JSONSL_SPECIALf_SIGNED)
301
+
302
+ #define STATE_NUM_LAST jsn->tok_last
303
+
304
+ #define CONTINUE_NEXT_CHAR() continue
305
+
306
+ const jsonsl_uchar_t *c = (jsonsl_uchar_t*)bytes;
307
+ size_t levels_max = jsn->levels_max;
308
+ struct jsonsl_state_st *state = jsn->stack + jsn->level;
309
+ jsn->base = bytes;
310
+
311
+ for (; nbytes; nbytes--, jsn->pos++, c++) {
312
+ unsigned state_type;
313
+ INCR_METRIC(TOTAL);
314
+
315
+ GT_AGAIN:
316
+ state_type = state->type;
317
+ /* Most common type is typically a string: */
318
+ if (state_type & JSONSL_Tf_STRINGY) {
319
+ /* Special escape handling for some stuff */
320
+ if (jsn->in_escape) {
321
+ jsn->in_escape = 0;
322
+ if (!is_allowed_escape(CUR_CHAR)) {
323
+ INVOKE_ERROR(ESCAPE_INVALID);
324
+ } else if (CUR_CHAR == 'u') {
325
+ DO_CALLBACK(UESCAPE, UESCAPE);
326
+ if (jsn->return_UESCAPE) {
327
+ return;
328
+ }
329
+ }
330
+ CONTINUE_NEXT_CHAR();
331
+ }
332
+
333
+ if (jsonsl__str_fastparse(jsn, &c, &nbytes) ==
334
+ FASTPARSE_EXHAUSTED) {
335
+ /* No need to readjust variables as we've exhausted the iterator */
336
+ return;
337
+ } else {
338
+ if (CUR_CHAR == '"') {
339
+ goto GT_QUOTE;
340
+ } else if (CUR_CHAR == '\\') {
341
+ goto GT_ESCAPE;
342
+ } else {
343
+ INVOKE_ERROR(WEIRD_WHITESPACE);
344
+ }
345
+ }
346
+ INCR_METRIC(STRINGY_SLOWPATH);
347
+
348
+ } else if (state_type == JSONSL_T_SPECIAL) {
349
+ /* Fast track for signed/unsigned */
350
+ if (IS_NORMAL_NUMBER) {
351
+ if (jsonsl__num_fastparse(jsn, &c, &nbytes, state) ==
352
+ FASTPARSE_EXHAUSTED) {
353
+ return;
354
+ } else {
355
+ goto GT_SPECIAL_NUMERIC;
356
+ }
357
+ } else if (state->special_flags == JSONSL_SPECIALf_DASH) {
358
+ #ifdef JSONSL_PARSE_NAN
359
+ if (CUR_CHAR == 'I' || CUR_CHAR == 'i') {
360
+ /* parsing -Infinity? */
361
+ state->special_flags = JSONSL_SPECIALf_NEG_INF;
362
+ CONTINUE_NEXT_CHAR();
363
+ }
364
+ #endif
365
+
366
+ if (!isdigit(CUR_CHAR)) {
367
+ INVOKE_ERROR(INVALID_NUMBER);
368
+ }
369
+
370
+ if (CUR_CHAR == '0') {
371
+ state->special_flags = JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED;
372
+ } else if (isdigit(CUR_CHAR)) {
373
+ state->special_flags = JSONSL_SPECIALf_SIGNED;
374
+ state->nelem = CUR_CHAR - 0x30;
375
+ } else {
376
+ INVOKE_ERROR(INVALID_NUMBER);
377
+ }
378
+ CONTINUE_NEXT_CHAR();
379
+
380
+ } else if (state->special_flags == JSONSL_SPECIALf_ZERO) {
381
+ if (isdigit(CUR_CHAR)) {
382
+ /* Following a zero! */
383
+ INVOKE_ERROR(INVALID_NUMBER);
384
+ }
385
+ /* Unset the 'zero' flag: */
386
+ if (state->special_flags & JSONSL_SPECIALf_SIGNED) {
387
+ state->special_flags = JSONSL_SPECIALf_SIGNED;
388
+ } else {
389
+ state->special_flags = JSONSL_SPECIALf_UNSIGNED;
390
+ }
391
+ goto GT_SPECIAL_NUMERIC;
392
+ }
393
+
394
+ if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) &&
395
+ !(state->special_flags & JSONSL_SPECIALf_INF)) {
396
+ GT_SPECIAL_NUMERIC:
397
+ switch (CUR_CHAR) {
398
+ CASE_DIGITS
399
+ STATE_NUM_LAST = '1';
400
+ CONTINUE_NEXT_CHAR();
401
+
402
+ case '.':
403
+ if (state->special_flags & JSONSL_SPECIALf_FLOAT) {
404
+ INVOKE_ERROR(INVALID_NUMBER);
405
+ }
406
+ state->special_flags |= JSONSL_SPECIALf_FLOAT;
407
+ STATE_NUM_LAST = '.';
408
+ CONTINUE_NEXT_CHAR();
409
+
410
+ case 'e':
411
+ case 'E':
412
+ if (state->special_flags & JSONSL_SPECIALf_EXPONENT) {
413
+ INVOKE_ERROR(INVALID_NUMBER);
414
+ }
415
+ state->special_flags |= JSONSL_SPECIALf_EXPONENT;
416
+ STATE_NUM_LAST = 'e';
417
+ CONTINUE_NEXT_CHAR();
418
+
419
+ case '-':
420
+ case '+':
421
+ if (STATE_NUM_LAST != 'e') {
422
+ INVOKE_ERROR(INVALID_NUMBER);
423
+ }
424
+ STATE_NUM_LAST = '-';
425
+ CONTINUE_NEXT_CHAR();
426
+
427
+ default:
428
+ if (is_special_end(CUR_CHAR)) {
429
+ goto GT_SPECIAL_POP;
430
+ }
431
+ INVOKE_ERROR(INVALID_NUMBER);
432
+ break;
433
+ }
434
+ }
435
+ /* else if (!NUMERIC) */
436
+ if (!is_special_end(CUR_CHAR)) {
437
+ STATE_SPECIAL_LENGTH++;
438
+
439
+ /* Verify TRUE, FALSE, NULL */
440
+ if (state->special_flags == JSONSL_SPECIALf_TRUE) {
441
+ VERIFY_SPECIAL("true");
442
+ } else if (state->special_flags == JSONSL_SPECIALf_FALSE) {
443
+ VERIFY_SPECIAL("false");
444
+ } else if (state->special_flags == JSONSL_SPECIALf_NULL) {
445
+ VERIFY_SPECIAL("null");
446
+ #ifdef JSONSL_PARSE_NAN
447
+ } else if (state->special_flags == JSONSL_SPECIALf_POS_INF) {
448
+ VERIFY_SPECIAL_CI("infinity");
449
+ } else if (state->special_flags == JSONSL_SPECIALf_NEG_INF) {
450
+ VERIFY_SPECIAL_CI("-infinity");
451
+ } else if (state->special_flags == JSONSL_SPECIALf_NAN) {
452
+ VERIFY_SPECIAL_CI("nan");
453
+ } else if (state->special_flags & JSONSL_SPECIALf_NULL ||
454
+ state->special_flags & JSONSL_SPECIALf_NAN) {
455
+ /* previous char was "n", are we parsing null or nan? */
456
+ if (CUR_CHAR != 'u') {
457
+ state->special_flags &= ~JSONSL_SPECIALf_NULL;
458
+ }
459
+
460
+ if (tolower(CUR_CHAR) != 'a') {
461
+ state->special_flags &= ~JSONSL_SPECIALf_NAN;
462
+ }
463
+ #endif
464
+ }
465
+ INCR_METRIC(SPECIAL_FASTPATH);
466
+ CONTINUE_NEXT_CHAR();
467
+ }
468
+
469
+ GT_SPECIAL_POP:
470
+ jsn->can_insert = 0;
471
+ if (IS_NORMAL_NUMBER) {
472
+ /* Nothing */
473
+ } else if (state->special_flags == JSONSL_SPECIALf_ZERO ||
474
+ state->special_flags == (JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED)) {
475
+ /* 0 is unsigned! */
476
+ state->special_flags = JSONSL_SPECIALf_UNSIGNED;
477
+ } else if (state->special_flags == JSONSL_SPECIALf_DASH) {
478
+ /* Still in dash! */
479
+ INVOKE_ERROR(INVALID_NUMBER);
480
+ } else if (state->special_flags & JSONSL_SPECIALf_INF) {
481
+ if (STATE_SPECIAL_LENGTH != 8) {
482
+ INVOKE_ERROR(SPECIAL_INCOMPLETE);
483
+ }
484
+ state->nelem = 1;
485
+ } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
486
+ /* Check that we're not at the end of a token */
487
+ if (STATE_NUM_LAST != '1') {
488
+ INVOKE_ERROR(INVALID_NUMBER);
489
+ }
490
+ } else if (state->special_flags == JSONSL_SPECIALf_TRUE) {
491
+ if (STATE_SPECIAL_LENGTH != 4) {
492
+ INVOKE_ERROR(SPECIAL_INCOMPLETE);
493
+ }
494
+ state->nelem = 1;
495
+ } else if (state->special_flags == JSONSL_SPECIALf_FALSE) {
496
+ if (STATE_SPECIAL_LENGTH != 5) {
497
+ INVOKE_ERROR(SPECIAL_INCOMPLETE);
498
+ }
499
+ } else if (state->special_flags == JSONSL_SPECIALf_NULL) {
500
+ if (STATE_SPECIAL_LENGTH != 4) {
501
+ INVOKE_ERROR(SPECIAL_INCOMPLETE);
502
+ }
503
+ }
504
+ SPECIAL_POP;
505
+ jsn->expecting = ',';
506
+ if (is_allowed_whitespace(CUR_CHAR)) {
507
+ CONTINUE_NEXT_CHAR();
508
+ }
509
+ /**
510
+ * This works because we have a non-whitespace token
511
+ * which is not a special token. If this is a structural
512
+ * character then it will be gracefully handled by the
513
+ * switch statement. Otherwise it will default to the 'special'
514
+ * state again,
515
+ */
516
+ goto GT_STRUCTURAL_TOKEN;
517
+ } else if (is_allowed_whitespace(CUR_CHAR)) {
518
+ INCR_METRIC(ALLOWED_WHITESPACE);
519
+ /* So we're not special. Harmless insignificant whitespace
520
+ * passthrough
521
+ */
522
+ CONTINUE_NEXT_CHAR();
523
+ } else if (extract_special(CUR_CHAR)) {
524
+ /* not a string, whitespace, or structural token. must be special */
525
+ goto GT_SPECIAL_BEGIN;
526
+ }
527
+
528
+ INCR_GENERIC(CUR_CHAR);
529
+
530
+ if (CUR_CHAR == '"') {
531
+ GT_QUOTE:
532
+ jsn->can_insert = 0;
533
+ switch (state_type) {
534
+
535
+ /* the end of a string or hash key */
536
+ case JSONSL_T_STRING:
537
+ CALLBACK_AND_POP(STRING);
538
+ CONTINUE_NEXT_CHAR();
539
+ case JSONSL_T_HKEY:
540
+ CALLBACK_AND_POP(HKEY);
541
+ CONTINUE_NEXT_CHAR();
542
+
543
+ case JSONSL_T_OBJECT:
544
+ state->nelem++;
545
+ if ( (state->nelem-1) % 2 ) {
546
+ /* Odd, this must be a hash value */
547
+ if (jsn->tok_last != ':') {
548
+ INVOKE_ERROR(MISSING_TOKEN);
549
+ }
550
+ jsn->expecting = ','; /* Can't figure out what to expect next */
551
+ jsn->tok_last = 0;
552
+
553
+ STACK_PUSH;
554
+ state->type = JSONSL_T_STRING;
555
+ DO_CALLBACK(STRING, PUSH);
556
+
557
+ } else {
558
+ /* hash key */
559
+ if (jsn->expecting != '"') {
560
+ INVOKE_ERROR(STRAY_TOKEN);
561
+ }
562
+ jsn->tok_last = 0;
563
+ jsn->expecting = ':';
564
+
565
+ STACK_PUSH;
566
+ state->type = JSONSL_T_HKEY;
567
+ DO_CALLBACK(HKEY, PUSH);
568
+ }
569
+ CONTINUE_NEXT_CHAR();
570
+
571
+ case JSONSL_T_LIST:
572
+ state->nelem++;
573
+ STACK_PUSH;
574
+ state->type = JSONSL_T_STRING;
575
+ jsn->expecting = ',';
576
+ jsn->tok_last = 0;
577
+ DO_CALLBACK(STRING, PUSH);
578
+ CONTINUE_NEXT_CHAR();
579
+
580
+ case JSONSL_T_SPECIAL:
581
+ INVOKE_ERROR(STRAY_TOKEN);
582
+ break;
583
+
584
+ default:
585
+ INVOKE_ERROR(STRING_OUTSIDE_CONTAINER);
586
+ break;
587
+ } /* switch(state->type) */
588
+ } else if (CUR_CHAR == '\\') {
589
+ GT_ESCAPE:
590
+ INCR_METRIC(ESCAPES);
591
+ /* Escape */
592
+ if ( (state->type & JSONSL_Tf_STRINGY) == 0 ) {
593
+ INVOKE_ERROR(ESCAPE_OUTSIDE_STRING);
594
+ }
595
+ state->nescapes++;
596
+ jsn->in_escape = 1;
597
+ CONTINUE_NEXT_CHAR();
598
+ } /* " or \ */
599
+
600
+ GT_STRUCTURAL_TOKEN:
601
+ switch (CUR_CHAR) {
602
+ case ':':
603
+ INCR_METRIC(STRUCTURAL_TOKEN);
604
+ if (jsn->expecting != CUR_CHAR) {
605
+ INVOKE_ERROR(STRAY_TOKEN);
606
+ }
607
+ jsn->tok_last = ':';
608
+ jsn->can_insert = 1;
609
+ jsn->expecting = '"';
610
+ CONTINUE_NEXT_CHAR();
611
+
612
+ case ',':
613
+ INCR_METRIC(STRUCTURAL_TOKEN);
614
+ /**
615
+ * The comma is one of the more generic tokens.
616
+ * In the context of an OBJECT, the can_insert flag
617
+ * should never be set, and no other action is
618
+ * necessary.
619
+ */
620
+ if (jsn->expecting != CUR_CHAR) {
621
+ /* make this branch execute only when we haven't manually
622
+ * just placed the ',' in the expecting register.
623
+ */
624
+ INVOKE_ERROR(STRAY_TOKEN);
625
+ }
626
+
627
+ if (state->type == JSONSL_T_OBJECT) {
628
+ /* end of hash value, expect a string as a hash key */
629
+ jsn->expecting = '"';
630
+ } else {
631
+ jsn->can_insert = 1;
632
+ }
633
+
634
+ jsn->tok_last = ',';
635
+ jsn->expecting = '"';
636
+ CONTINUE_NEXT_CHAR();
637
+
638
+ /* new list or object */
639
+ /* hashes are more common */
640
+ case '{':
641
+ case '[':
642
+ INCR_METRIC(STRUCTURAL_TOKEN);
643
+ if (!jsn->can_insert) {
644
+ INVOKE_ERROR(CANT_INSERT);
645
+ }
646
+
647
+ ENSURE_HVAL;
648
+ state->nelem++;
649
+
650
+ STACK_PUSH;
651
+ /* because the constants match the opening delimiters, we can do this: */
652
+ state->type = CUR_CHAR;
653
+ state->nelem = 0;
654
+ jsn->can_insert = 1;
655
+ if (CUR_CHAR == '{') {
656
+ /* If we're a hash, we expect a key first, which is quouted */
657
+ jsn->expecting = '"';
658
+ }
659
+ if (CUR_CHAR == JSONSL_T_OBJECT) {
660
+ DO_CALLBACK(OBJECT, PUSH);
661
+ } else {
662
+ DO_CALLBACK(LIST, PUSH);
663
+ }
664
+ jsn->tok_last = 0;
665
+ CONTINUE_NEXT_CHAR();
666
+
667
+ /* closing of list or object */
668
+ case '}':
669
+ case ']':
670
+ INCR_METRIC(STRUCTURAL_TOKEN);
671
+ if (jsn->tok_last == ',' && jsn->options.allow_trailing_comma == 0) {
672
+ INVOKE_ERROR(TRAILING_COMMA);
673
+ }
674
+
675
+ jsn->can_insert = 0;
676
+ jsn->level--;
677
+ jsn->expecting = ',';
678
+ jsn->tok_last = 0;
679
+ if (CUR_CHAR == ']') {
680
+ if (state->type != '[') {
681
+ INVOKE_ERROR(BRACKET_MISMATCH);
682
+ }
683
+ DO_CALLBACK(LIST, POP);
684
+ } else {
685
+ if (state->type != '{') {
686
+ INVOKE_ERROR(BRACKET_MISMATCH);
687
+ } else if (state->nelem && state->nelem % 2 != 0) {
688
+ INVOKE_ERROR(VALUE_EXPECTED);
689
+ }
690
+ DO_CALLBACK(OBJECT, POP);
691
+ }
692
+ state = jsn->stack + jsn->level;
693
+ state->pos_cur = jsn->pos;
694
+ CONTINUE_NEXT_CHAR();
695
+
696
+ default:
697
+ GT_SPECIAL_BEGIN:
698
+ /**
699
+ * Not a string, not a structural token, and not benign whitespace.
700
+ * Technically we should iterate over the character always, but since
701
+ * we are not doing full numerical/value decoding anyway (but only hinting),
702
+ * we only check upon entry.
703
+ */
704
+ if (state->type != JSONSL_T_SPECIAL) {
705
+ int special_flags = extract_special(CUR_CHAR);
706
+ if (!special_flags) {
707
+ /**
708
+ * Try to do some heuristics here anyway to figure out what kind of
709
+ * error this is. The 'special' case is a fallback scenario anyway.
710
+ */
711
+ if (CUR_CHAR == '\0') {
712
+ INVOKE_ERROR(FOUND_NULL_BYTE);
713
+ } else if (CUR_CHAR < 0x20) {
714
+ INVOKE_ERROR(WEIRD_WHITESPACE);
715
+ } else {
716
+ INVOKE_ERROR(SPECIAL_EXPECTED);
717
+ }
718
+ }
719
+ ENSURE_HVAL;
720
+ state->nelem++;
721
+ if (!jsn->can_insert) {
722
+ INVOKE_ERROR(CANT_INSERT);
723
+ }
724
+ STACK_PUSH;
725
+ state->type = JSONSL_T_SPECIAL;
726
+ state->special_flags = special_flags;
727
+ STATE_SPECIAL_LENGTH = 1;
728
+
729
+ if (special_flags == JSONSL_SPECIALf_UNSIGNED) {
730
+ state->nelem = CUR_CHAR - 0x30;
731
+ STATE_NUM_LAST = '1';
732
+ } else {
733
+ STATE_NUM_LAST = '-';
734
+ state->nelem = 0;
735
+ }
736
+ DO_CALLBACK(SPECIAL, PUSH);
737
+ }
738
+ CONTINUE_NEXT_CHAR();
739
+ }
740
+ }
741
+ }
742
+
743
+ JSONSL_API
744
+ const char* jsonsl_strerror(jsonsl_error_t err)
745
+ {
746
+ if (err == JSONSL_ERROR_SUCCESS) {
747
+ return "SUCCESS";
748
+ }
749
+ #define X(t) \
750
+ if (err == JSONSL_ERROR_##t) \
751
+ return #t;
752
+ JSONSL_XERR;
753
+ #undef X
754
+ return "<UNKNOWN_ERROR>";
755
+ }
756
+
757
+ JSONSL_API
758
+ const char *jsonsl_strtype(jsonsl_type_t type)
759
+ {
760
+ #define X(o,c) \
761
+ if (type == JSONSL_T_##o) \
762
+ return #o;
763
+ JSONSL_XTYPE
764
+ #undef X
765
+ return "UNKNOWN TYPE";
766
+
767
+ }
768
+
769
+ /*
770
+ *
771
+ * JPR/JSONPointer functions
772
+ *
773
+ *
774
+ */
775
+ #ifndef JSONSL_NO_JPR
776
+ static
777
+ jsonsl_jpr_type_t
778
+ populate_component(char *in,
779
+ struct jsonsl_jpr_component_st *component,
780
+ char **next,
781
+ jsonsl_error_t *errp)
782
+ {
783
+ unsigned long pctval;
784
+ char *c = NULL, *outp = NULL, *end = NULL;
785
+ size_t input_len;
786
+ jsonsl_jpr_type_t ret = JSONSL_PATH_NONE;
787
+
788
+ if (*next == NULL || *(*next) == '\0') {
789
+ return JSONSL_PATH_NONE;
790
+ }
791
+
792
+ /* Replace the next / with a NULL */
793
+ *next = strstr(in, "/");
794
+ if (*next != NULL) {
795
+ *(*next) = '\0'; /* drop the forward slash */
796
+ input_len = *next - in;
797
+ end = *next;
798
+ *next += 1; /* next character after the '/' */
799
+ } else {
800
+ input_len = strlen(in);
801
+ end = in + input_len + 1;
802
+ }
803
+
804
+ component->pstr = in;
805
+
806
+ /* Check for special components of interest */
807
+ if (*in == JSONSL_PATH_WILDCARD_CHAR && input_len == 1) {
808
+ /* Lone wildcard */
809
+ ret = JSONSL_PATH_WILDCARD;
810
+ goto GT_RET;
811
+ } else if (isdigit(*in)) {
812
+ /* ASCII Numeric */
813
+ char *endptr;
814
+ component->idx = strtoul(in, &endptr, 10);
815
+ if (endptr && *endptr == '\0') {
816
+ ret = JSONSL_PATH_NUMERIC;
817
+ goto GT_RET;
818
+ }
819
+ }
820
+
821
+ /* Default, it's a string */
822
+ ret = JSONSL_PATH_STRING;
823
+ for (c = outp = in; c < end; c++, outp++) {
824
+ char origc;
825
+ if (*c != '%') {
826
+ goto GT_ASSIGN;
827
+ }
828
+ /*
829
+ * c = { [+0] = '%', [+1] = 'b', [+2] = 'e', [+3] = '\0' }
830
+ */
831
+
832
+ /* Need %XX */
833
+ if (c+2 >= end) {
834
+ *errp = JSONSL_ERROR_PERCENT_BADHEX;
835
+ return JSONSL_PATH_INVALID;
836
+ }
837
+ if (! (isxdigit(*(c+1)) && isxdigit(*(c+2))) ) {
838
+ *errp = JSONSL_ERROR_PERCENT_BADHEX;
839
+ return JSONSL_PATH_INVALID;
840
+ }
841
+
842
+ /* Temporarily null-terminate the characters */
843
+ origc = *(c+3);
844
+ *(c+3) = '\0';
845
+ pctval = strtoul(c+1, NULL, 16);
846
+ *(c+3) = origc;
847
+
848
+ *outp = (char) pctval;
849
+ c += 2;
850
+ continue;
851
+
852
+ GT_ASSIGN:
853
+ *outp = *c;
854
+ }
855
+ /* Null-terminate the string */
856
+ for (; outp < c; outp++) {
857
+ *outp = '\0';
858
+ }
859
+
860
+ GT_RET:
861
+ component->ptype = ret;
862
+ if (ret != JSONSL_PATH_WILDCARD) {
863
+ component->len = strlen(component->pstr);
864
+ }
865
+ return ret;
866
+ }
867
+
868
+ JSONSL_API
869
+ jsonsl_jpr_t
870
+ jsonsl_jpr_new(const char *path, jsonsl_error_t *errp)
871
+ {
872
+ char *my_copy = NULL;
873
+ int count, curidx;
874
+ struct jsonsl_jpr_st *ret = NULL;
875
+ struct jsonsl_jpr_component_st *components = NULL;
876
+ size_t origlen;
877
+ jsonsl_error_t errstacked;
878
+
879
+ #define JPR_BAIL(err) *errp = err; goto GT_ERROR;
880
+
881
+ if (errp == NULL) {
882
+ errp = &errstacked;
883
+ }
884
+
885
+ if (path == NULL || *path != '/') {
886
+ JPR_BAIL(JSONSL_ERROR_JPR_NOROOT);
887
+ }
888
+
889
+ count = 1;
890
+ path++;
891
+ {
892
+ const char *c = path;
893
+ for (; *c; c++) {
894
+ if (*c == '/') {
895
+ count++;
896
+ if (*(c+1) == '/') {
897
+ JPR_BAIL(JSONSL_ERROR_JPR_DUPSLASH);
898
+ }
899
+ }
900
+ }
901
+ }
902
+ if(*path) {
903
+ count++;
904
+ }
905
+
906
+ components = (struct jsonsl_jpr_component_st *)
907
+ malloc(sizeof(*components) * count);
908
+ if (!components) {
909
+ JPR_BAIL(JSONSL_ERROR_ENOMEM);
910
+ }
911
+
912
+ my_copy = (char *)malloc(strlen(path) + 1);
913
+ if (!my_copy) {
914
+ JPR_BAIL(JSONSL_ERROR_ENOMEM);
915
+ }
916
+
917
+ strcpy(my_copy, path);
918
+
919
+ components[0].ptype = JSONSL_PATH_ROOT;
920
+
921
+ if (*my_copy) {
922
+ char *cur = my_copy;
923
+ int pathret = JSONSL_PATH_STRING;
924
+ curidx = 1;
925
+ while (curidx < count) {
926
+ pathret = populate_component(cur, components + curidx, &cur, errp);
927
+ if (pathret > 0) {
928
+ curidx++;
929
+ } else {
930
+ break;
931
+ }
932
+ }
933
+
934
+ if (pathret == JSONSL_PATH_INVALID) {
935
+ JPR_BAIL(JSONSL_ERROR_JPR_BADPATH);
936
+ }
937
+ } else {
938
+ curidx = 1;
939
+ }
940
+
941
+ path--; /*revert path to leading '/' */
942
+ origlen = strlen(path) + 1;
943
+ ret = (struct jsonsl_jpr_st *)malloc(sizeof(*ret));
944
+ if (!ret) {
945
+ JPR_BAIL(JSONSL_ERROR_ENOMEM);
946
+ }
947
+ ret->orig = (char *)malloc(origlen);
948
+ if (!ret->orig) {
949
+ JPR_BAIL(JSONSL_ERROR_ENOMEM);
950
+ }
951
+ ret->components = components;
952
+ ret->ncomponents = curidx;
953
+ ret->basestr = my_copy;
954
+ ret->norig = origlen-1;
955
+ strcpy(ret->orig, path);
956
+
957
+ return ret;
958
+
959
+ GT_ERROR:
960
+ free(my_copy);
961
+ free(components);
962
+ if (ret) {
963
+ free(ret->orig);
964
+ }
965
+ free(ret);
966
+ return NULL;
967
+ #undef JPR_BAIL
968
+ }
969
+
970
+ void jsonsl_jpr_destroy(jsonsl_jpr_t jpr)
971
+ {
972
+ free(jpr->components);
973
+ free(jpr->basestr);
974
+ free(jpr->orig);
975
+ free(jpr);
976
+ }
977
+
978
+ /**
979
+ * Call when there is a possibility of a match, either as a final match or
980
+ * as a path within a match
981
+ * @param jpr The JPR path
982
+ * @param component Component corresponding to the current element
983
+ * @param prlevel The level of the *parent*
984
+ * @param chtype The type of the child
985
+ * @return Match status
986
+ */
987
+ static jsonsl_jpr_match_t
988
+ jsonsl__match_continue(jsonsl_jpr_t jpr,
989
+ const struct jsonsl_jpr_component_st *component,
990
+ unsigned prlevel, unsigned chtype)
991
+ {
992
+ const struct jsonsl_jpr_component_st *next_comp = component + 1;
993
+ if (prlevel == jpr->ncomponents - 1) {
994
+ /* This is the match. Check the expected type of the match against
995
+ * the child */
996
+ if (jpr->match_type == 0 || jpr->match_type == chtype) {
997
+ return JSONSL_MATCH_COMPLETE;
998
+ } else {
999
+ return JSONSL_MATCH_TYPE_MISMATCH;
1000
+ }
1001
+ }
1002
+ if (chtype == JSONSL_T_LIST) {
1003
+ if (next_comp->ptype == JSONSL_PATH_NUMERIC) {
1004
+ return JSONSL_MATCH_POSSIBLE;
1005
+ } else {
1006
+ return JSONSL_MATCH_TYPE_MISMATCH;
1007
+ }
1008
+ } else if (chtype == JSONSL_T_OBJECT) {
1009
+ if (next_comp->ptype == JSONSL_PATH_NUMERIC) {
1010
+ return JSONSL_MATCH_TYPE_MISMATCH;
1011
+ } else {
1012
+ return JSONSL_MATCH_POSSIBLE;
1013
+ }
1014
+ } else {
1015
+ return JSONSL_MATCH_TYPE_MISMATCH;
1016
+ }
1017
+ }
1018
+
1019
+ JSONSL_API
1020
+ jsonsl_jpr_match_t
1021
+ jsonsl_path_match(jsonsl_jpr_t jpr,
1022
+ const struct jsonsl_state_st *parent,
1023
+ const struct jsonsl_state_st *child,
1024
+ const char *key, size_t nkey)
1025
+ {
1026
+ const struct jsonsl_jpr_component_st *comp;
1027
+ if (!parent) {
1028
+ /* No parent. Return immediately since it's always a match */
1029
+ return jsonsl__match_continue(jpr, jpr->components, 0, child->type);
1030
+ }
1031
+
1032
+ comp = jpr->components + parent->level;
1033
+
1034
+ /* note that we don't need to verify the type of the match, this is
1035
+ * always done through the previous call to jsonsl__match_continue.
1036
+ * If we are in a POSSIBLE tree then we can be certain the types (at
1037
+ * least at this level) are correct */
1038
+ if (parent->type == JSONSL_T_OBJECT) {
1039
+ if (comp->len != nkey || strncmp(key, comp->pstr, nkey) != 0) {
1040
+ return JSONSL_MATCH_NOMATCH;
1041
+ }
1042
+ } else {
1043
+ if (comp->idx != parent->nelem - 1) {
1044
+ return JSONSL_MATCH_NOMATCH;
1045
+ }
1046
+ }
1047
+ return jsonsl__match_continue(jpr, comp, parent->level, child->type);
1048
+ }
1049
+
1050
+ JSONSL_API
1051
+ jsonsl_jpr_match_t
1052
+ jsonsl_jpr_match(jsonsl_jpr_t jpr,
1053
+ unsigned int parent_type,
1054
+ unsigned int parent_level,
1055
+ const char *key,
1056
+ size_t nkey)
1057
+ {
1058
+ /* find our current component. This is the child level */
1059
+ int cmpret;
1060
+ struct jsonsl_jpr_component_st *p_component;
1061
+ p_component = jpr->components + parent_level;
1062
+
1063
+ if (parent_level >= jpr->ncomponents) {
1064
+ return JSONSL_MATCH_NOMATCH;
1065
+ }
1066
+
1067
+ /* Lone query for 'root' element. Always matches */
1068
+ if (parent_level == 0) {
1069
+ if (jpr->ncomponents == 1) {
1070
+ return JSONSL_MATCH_COMPLETE;
1071
+ } else {
1072
+ return JSONSL_MATCH_POSSIBLE;
1073
+ }
1074
+ }
1075
+
1076
+ /* Wildcard, always matches */
1077
+ if (p_component->ptype == JSONSL_PATH_WILDCARD) {
1078
+ if (parent_level == jpr->ncomponents-1) {
1079
+ return JSONSL_MATCH_COMPLETE;
1080
+ } else {
1081
+ return JSONSL_MATCH_POSSIBLE;
1082
+ }
1083
+ }
1084
+
1085
+ /* Check numeric array index. This gets its special block so we can avoid
1086
+ * string comparisons */
1087
+ if (p_component->ptype == JSONSL_PATH_NUMERIC) {
1088
+ if (parent_type == JSONSL_T_LIST) {
1089
+ if (p_component->idx != nkey) {
1090
+ /* Wrong index */
1091
+ return JSONSL_MATCH_NOMATCH;
1092
+ } else {
1093
+ if (parent_level == jpr->ncomponents-1) {
1094
+ /* This is the last element of the path */
1095
+ return JSONSL_MATCH_COMPLETE;
1096
+ } else {
1097
+ /* Intermediate element */
1098
+ return JSONSL_MATCH_POSSIBLE;
1099
+ }
1100
+ }
1101
+ } else if (p_component->is_arridx) {
1102
+ /* Numeric and an array index (set explicitly by user). But not
1103
+ * a list for a parent */
1104
+ return JSONSL_MATCH_TYPE_MISMATCH;
1105
+ }
1106
+ } else if (parent_type == JSONSL_T_LIST) {
1107
+ return JSONSL_MATCH_TYPE_MISMATCH;
1108
+ }
1109
+
1110
+ /* Check lengths */
1111
+ if (p_component->len != nkey) {
1112
+ return JSONSL_MATCH_NOMATCH;
1113
+ }
1114
+
1115
+ /* Check string comparison */
1116
+ cmpret = strncmp(p_component->pstr, key, nkey);
1117
+ if (cmpret == 0) {
1118
+ if (parent_level == jpr->ncomponents-1) {
1119
+ return JSONSL_MATCH_COMPLETE;
1120
+ } else {
1121
+ return JSONSL_MATCH_POSSIBLE;
1122
+ }
1123
+ }
1124
+
1125
+ return JSONSL_MATCH_NOMATCH;
1126
+ }
1127
+
1128
+ JSONSL_API
1129
+ void jsonsl_jpr_match_state_init(jsonsl_t jsn,
1130
+ jsonsl_jpr_t *jprs,
1131
+ size_t njprs)
1132
+ {
1133
+ size_t ii, *firstjmp;
1134
+ if (njprs == 0) {
1135
+ return;
1136
+ }
1137
+ jsn->jprs = (jsonsl_jpr_t *)malloc(sizeof(jsonsl_jpr_t) * njprs);
1138
+ jsn->jpr_count = njprs;
1139
+ jsn->jpr_root = (size_t*)calloc(1, sizeof(size_t) * njprs * jsn->levels_max);
1140
+ memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs);
1141
+ /* Set the initial jump table values */
1142
+
1143
+ firstjmp = jsn->jpr_root;
1144
+ for (ii = 0; ii < njprs; ii++) {
1145
+ firstjmp[ii] = ii+1;
1146
+ }
1147
+ }
1148
+
1149
+ JSONSL_API
1150
+ void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn)
1151
+ {
1152
+ if (jsn->jpr_count == 0) {
1153
+ return;
1154
+ }
1155
+
1156
+ free(jsn->jpr_root);
1157
+ free(jsn->jprs);
1158
+ jsn->jprs = NULL;
1159
+ jsn->jpr_root = NULL;
1160
+ jsn->jpr_count = 0;
1161
+ }
1162
+
1163
+ /**
1164
+ * This function should be called exactly once on each element...
1165
+ * This should also be called in recursive order, since we rely
1166
+ * on the parent having been initalized for a match.
1167
+ *
1168
+ * Since the parent is checked for a match as well, we maintain a 'serial' counter.
1169
+ * Whenever we traverse an element, we expect the serial to be the same as a global
1170
+ * integer. If they do not match, we re-initialize the context, and set the serial.
1171
+ *
1172
+ * This ensures a type of consistency without having a proactive reset by the
1173
+ * main lexer itself.
1174
+ *
1175
+ */
1176
+ JSONSL_API
1177
+ jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn,
1178
+ struct jsonsl_state_st *state,
1179
+ const char *key,
1180
+ size_t nkey,
1181
+ jsonsl_jpr_match_t *out)
1182
+ {
1183
+ struct jsonsl_state_st *parent_state;
1184
+ jsonsl_jpr_t ret = NULL;
1185
+
1186
+ /* Jump and JPR tables for our own state and the parent state */
1187
+ size_t *jmptable, *pjmptable;
1188
+ size_t jmp_cur, ii, ourjmpidx;
1189
+
1190
+ if (!jsn->jpr_root) {
1191
+ *out = JSONSL_MATCH_NOMATCH;
1192
+ return NULL;
1193
+ }
1194
+
1195
+ pjmptable = jsn->jpr_root + (jsn->jpr_count * (state->level-1));
1196
+ jmptable = pjmptable + jsn->jpr_count;
1197
+
1198
+ /* If the parent cannot match, then invalidate it */
1199
+ if (*pjmptable == 0) {
1200
+ *jmptable = 0;
1201
+ *out = JSONSL_MATCH_NOMATCH;
1202
+ return NULL;
1203
+ }
1204
+
1205
+ parent_state = jsn->stack + state->level - 1;
1206
+
1207
+ if (parent_state->type == JSONSL_T_LIST) {
1208
+ nkey = (size_t) parent_state->nelem;
1209
+ }
1210
+
1211
+ *jmptable = 0;
1212
+ ourjmpidx = 0;
1213
+ memset(jmptable, 0, sizeof(int) * jsn->jpr_count);
1214
+
1215
+ for (ii = 0; ii < jsn->jpr_count; ii++) {
1216
+ jmp_cur = pjmptable[ii];
1217
+ if (jmp_cur) {
1218
+ jsonsl_jpr_t jpr = jsn->jprs[jmp_cur-1];
1219
+ *out = jsonsl_jpr_match(jpr,
1220
+ parent_state->type,
1221
+ parent_state->level,
1222
+ key, nkey);
1223
+ if (*out == JSONSL_MATCH_COMPLETE) {
1224
+ ret = jpr;
1225
+ *jmptable = 0;
1226
+ return ret;
1227
+ } else if (*out == JSONSL_MATCH_POSSIBLE) {
1228
+ jmptable[ourjmpidx] = ii+1;
1229
+ ourjmpidx++;
1230
+ }
1231
+ } else {
1232
+ break;
1233
+ }
1234
+ }
1235
+ if (!*jmptable) {
1236
+ *out = JSONSL_MATCH_NOMATCH;
1237
+ }
1238
+ return NULL;
1239
+ }
1240
+
1241
+ JSONSL_API
1242
+ const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match)
1243
+ {
1244
+ #define X(T,v) \
1245
+ if ( match == JSONSL_MATCH_##T ) \
1246
+ return #T;
1247
+ JSONSL_XMATCH
1248
+ #undef X
1249
+ return "<UNKNOWN>";
1250
+ }
1251
+
1252
+ #endif /* JSONSL_WITH_JPR */
1253
+
1254
+ static char *
1255
+ jsonsl__writeutf8(uint32_t pt, char *out)
1256
+ {
1257
+ #define ADD_OUTPUT(c) *out = (char)(c); out++;
1258
+
1259
+ if (pt < 0x80) {
1260
+ ADD_OUTPUT(pt);
1261
+ } else if (pt < 0x800) {
1262
+ ADD_OUTPUT((pt >> 6) | 0xC0);
1263
+ ADD_OUTPUT((pt & 0x3F) | 0x80);
1264
+ } else if (pt < 0x10000) {
1265
+ ADD_OUTPUT((pt >> 12) | 0xE0);
1266
+ ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80);
1267
+ ADD_OUTPUT((pt & 0x3F) | 0x80);
1268
+ } else {
1269
+ ADD_OUTPUT((pt >> 18) | 0xF0);
1270
+ ADD_OUTPUT(((pt >> 12) & 0x3F) | 0x80);
1271
+ ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80);
1272
+ ADD_OUTPUT((pt & 0x3F) | 0x80);
1273
+ }
1274
+ return out;
1275
+ #undef ADD_OUTPUT
1276
+ }
1277
+
1278
+ /* Thanks snej (https://github.com/mnunberg/jsonsl/issues/9) */
1279
+ static int
1280
+ jsonsl__digit2int(char ch) {
1281
+ int d = ch - '0';
1282
+ if ((unsigned) d < 10) {
1283
+ return d;
1284
+ }
1285
+ d = ch - 'a';
1286
+ if ((unsigned) d < 6) {
1287
+ return d + 10;
1288
+ }
1289
+ d = ch - 'A';
1290
+ if ((unsigned) d < 6) {
1291
+ return d + 10;
1292
+ }
1293
+ return -1;
1294
+ }
1295
+
1296
+ /* Assume 's' is at least 4 bytes long */
1297
+ static int
1298
+ jsonsl__get_uescape_16(const char *s)
1299
+ {
1300
+ int ret = 0;
1301
+ int cur;
1302
+
1303
+ #define GET_DIGIT(off) \
1304
+ cur = jsonsl__digit2int(s[off]); \
1305
+ if (cur == -1) { return -1; } \
1306
+ ret |= (cur << (12 - (off * 4)));
1307
+
1308
+ GET_DIGIT(0);
1309
+ GET_DIGIT(1);
1310
+ GET_DIGIT(2);
1311
+ GET_DIGIT(3);
1312
+ #undef GET_DIGIT
1313
+ return ret;
1314
+ }
1315
+
1316
+ /**
1317
+ * Utility function to convert escape sequences
1318
+ */
1319
+ JSONSL_API
1320
+ size_t jsonsl_util_unescape_ex(const char *in,
1321
+ char *out,
1322
+ size_t len,
1323
+ const int toEscape[128],
1324
+ unsigned *oflags,
1325
+ jsonsl_error_t *err,
1326
+ const char **errat)
1327
+ {
1328
+ const unsigned char *c = (const unsigned char*)in;
1329
+ char *begin_p = out;
1330
+ unsigned oflags_s;
1331
+ uint16_t last_codepoint = 0;
1332
+
1333
+ if (!oflags) {
1334
+ oflags = &oflags_s;
1335
+ }
1336
+ *oflags = 0;
1337
+
1338
+ #define UNESCAPE_BAIL(e,offset) \
1339
+ *err = JSONSL_ERROR_##e; \
1340
+ if (errat) { \
1341
+ *errat = (const char*)(c+ (ptrdiff_t)(offset)); \
1342
+ } \
1343
+ return 0;
1344
+
1345
+ for (; len; len--, c++, out++) {
1346
+ int uescval;
1347
+ if (*c != '\\') {
1348
+ /* Not an escape, so we don't care about this */
1349
+ goto GT_ASSIGN;
1350
+ }
1351
+
1352
+ if (len < 2) {
1353
+ UNESCAPE_BAIL(ESCAPE_INVALID, 0);
1354
+ }
1355
+ if (!is_allowed_escape(c[1])) {
1356
+ UNESCAPE_BAIL(ESCAPE_INVALID, 1)
1357
+ }
1358
+ if ((toEscape && toEscape[(unsigned char)c[1] & 0x7f] == 0 &&
1359
+ c[1] != '\\' && c[1] != '"')) {
1360
+ /* if we don't want to unescape this string, write the escape sequence to the output */
1361
+ *out++ = *c++;
1362
+ --len;
1363
+ goto GT_ASSIGN;
1364
+ }
1365
+
1366
+ if (c[1] != 'u') {
1367
+ /* simple skip-and-replace using pre-defined maps.
1368
+ * TODO: should the maps actually reflect the desired
1369
+ * replacement character in toEscape?
1370
+ */
1371
+ char esctmp = get_escape_equiv(c[1]);
1372
+ if (esctmp) {
1373
+ /* Check if there is a corresponding replacement */
1374
+ *out = esctmp;
1375
+ } else {
1376
+ /* Just gobble up the 'reverse-solidus' */
1377
+ *out = c[1];
1378
+ }
1379
+ len--;
1380
+ c++;
1381
+ /* do not assign, just continue */
1382
+ continue;
1383
+ }
1384
+
1385
+ /* next == 'u' */
1386
+ if (len < 6) {
1387
+ /* Need at least six characters.. */
1388
+ UNESCAPE_BAIL(UESCAPE_TOOSHORT, 2);
1389
+ }
1390
+
1391
+ uescval = jsonsl__get_uescape_16((const char *)c + 2);
1392
+ if (uescval == -1) {
1393
+ UNESCAPE_BAIL(PERCENT_BADHEX, -1);
1394
+ }
1395
+
1396
+ if (last_codepoint) {
1397
+ uint16_t w1 = last_codepoint, w2 = (uint16_t)uescval;
1398
+ uint32_t cp;
1399
+
1400
+ if (uescval < 0xDC00 || uescval > 0xDFFF) {
1401
+ UNESCAPE_BAIL(INVALID_CODEPOINT, -1);
1402
+ }
1403
+
1404
+ cp = (w1 & 0x3FF) << 10;
1405
+ cp |= (w2 & 0x3FF);
1406
+ cp += 0x10000;
1407
+
1408
+ out = jsonsl__writeutf8(cp, out) - 1;
1409
+ last_codepoint = 0;
1410
+
1411
+ } else if (uescval < 0xD800 || uescval > 0xDFFF) {
1412
+ *oflags |= JSONSL_SPECIALf_NONASCII;
1413
+ out = jsonsl__writeutf8(uescval, out) - 1;
1414
+
1415
+ } else if (uescval < 0xDC00) {
1416
+ *oflags |= JSONSL_SPECIALf_NONASCII;
1417
+ last_codepoint = (uint16_t)uescval;
1418
+ out--;
1419
+ } else {
1420
+ UNESCAPE_BAIL(INVALID_CODEPOINT, 2);
1421
+ }
1422
+
1423
+ /* Post uescape cleanup */
1424
+ len -= 5; /* Gobble up 5 chars after 'u' */
1425
+ c += 5;
1426
+ continue;
1427
+
1428
+ /* Only reached by previous branches */
1429
+ GT_ASSIGN:
1430
+ *out = *c;
1431
+ }
1432
+
1433
+ if (last_codepoint) {
1434
+ *err = JSONSL_ERROR_INVALID_CODEPOINT;
1435
+ return 0;
1436
+ }
1437
+
1438
+ *err = JSONSL_ERROR_SUCCESS;
1439
+ return out - begin_p;
1440
+ }
1441
+
1442
+ /**
1443
+ * Character Table definitions.
1444
+ * These were all generated via srcutil/genchartables.pl
1445
+ */
1446
+
1447
+ /**
1448
+ * This table contains the beginnings of non-string
1449
+ * allowable (bareword) values.
1450
+ */
1451
+ static unsigned short Special_Table[0x100] = {
1452
+ /* 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 */
1453
+ /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2c */
1454
+ /* 0x2d */ JSONSL_SPECIALf_DASH /* <-> */, /* 0x2d */
1455
+ /* 0x2e */ 0,0, /* 0x2f */
1456
+ /* 0x30 */ JSONSL_SPECIALf_ZERO /* <0> */, /* 0x30 */
1457
+ /* 0x31 */ JSONSL_SPECIALf_UNSIGNED /* <1> */, /* 0x31 */
1458
+ /* 0x32 */ JSONSL_SPECIALf_UNSIGNED /* <2> */, /* 0x32 */
1459
+ /* 0x33 */ JSONSL_SPECIALf_UNSIGNED /* <3> */, /* 0x33 */
1460
+ /* 0x34 */ JSONSL_SPECIALf_UNSIGNED /* <4> */, /* 0x34 */
1461
+ /* 0x35 */ JSONSL_SPECIALf_UNSIGNED /* <5> */, /* 0x35 */
1462
+ /* 0x36 */ JSONSL_SPECIALf_UNSIGNED /* <6> */, /* 0x36 */
1463
+ /* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */
1464
+ /* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */
1465
+ /* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */
1466
+ /* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x48 */
1467
+ /* 0x49 */ JSONSL__INF_PROXY /* <I> */, /* 0x49 */
1468
+ /* 0x4a */ 0,0,0,0, /* 0x4d */
1469
+ /* 0x4e */ JSONSL__NAN_PROXY /* <N> */, /* 0x4e */
1470
+ /* 0x4f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */
1471
+ /* 0x66 */ JSONSL_SPECIALf_FALSE /* <f> */, /* 0x66 */
1472
+ /* 0x67 */ 0,0, /* 0x68 */
1473
+ /* 0x69 */ JSONSL__INF_PROXY /* <i> */, /* 0x69 */
1474
+ /* 0x6a */ 0,0,0,0, /* 0x6d */
1475
+ /* 0x6e */ JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY /* <n> */, /* 0x6e */
1476
+ /* 0x6f */ 0,0,0,0,0, /* 0x73 */
1477
+ /* 0x74 */ JSONSL_SPECIALf_TRUE /* <t> */, /* 0x74 */
1478
+ /* 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 */
1479
+ /* 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 */
1480
+ /* 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 */
1481
+ /* 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 */
1482
+ /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0, /* 0xfe */
1483
+ };
1484
+
1485
+ /**
1486
+ * Contains characters which signal the termination of any of the 'special' bareword
1487
+ * values.
1488
+ */
1489
+ static int Special_Endings[0x100] = {
1490
+ /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */
1491
+ /* 0x09 */ 1 /* <TAB> */, /* 0x09 */
1492
+ /* 0x0a */ 1 /* <LF> */, /* 0x0a */
1493
+ /* 0x0b */ 0,0, /* 0x0c */
1494
+ /* 0x0d */ 1 /* <CR> */, /* 0x0d */
1495
+ /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1496
+ /* 0x20 */ 1 /* <SP> */, /* 0x20 */
1497
+ /* 0x21 */ 0, /* 0x21 */
1498
+ /* 0x22 */ 1 /* " */, /* 0x22 */
1499
+ /* 0x23 */ 0,0,0,0,0,0,0,0,0, /* 0x2b */
1500
+ /* 0x2c */ 1 /* , */, /* 0x2c */
1501
+ /* 0x2d */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x39 */
1502
+ /* 0x3a */ 1 /* : */, /* 0x3a */
1503
+ /* 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 */
1504
+ /* 0x5b */ 1 /* [ */, /* 0x5b */
1505
+ /* 0x5c */ 1 /* \ */, /* 0x5c */
1506
+ /* 0x5d */ 1 /* ] */, /* 0x5d */
1507
+ /* 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 */
1508
+ /* 0x7b */ 1 /* { */, /* 0x7b */
1509
+ /* 0x7c */ 0, /* 0x7c */
1510
+ /* 0x7d */ 1 /* } */, /* 0x7d */
1511
+ /* 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 */
1512
+ /* 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 */
1513
+ /* 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 */
1514
+ /* 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 */
1515
+ /* 0xfe */ 0 /* 0xfe */
1516
+ };
1517
+
1518
+ /**
1519
+ * This table contains entries for the allowed whitespace as per RFC 4627
1520
+ */
1521
+ static int Allowed_Whitespace[0x100] = {
1522
+ /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */
1523
+ /* 0x09 */ 1 /* <TAB> */, /* 0x09 */
1524
+ /* 0x0a */ 1 /* <LF> */, /* 0x0a */
1525
+ /* 0x0b */ 0,0, /* 0x0c */
1526
+ /* 0x0d */ 1 /* <CR> */, /* 0x0d */
1527
+ /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
1528
+ /* 0x20 */ 1 /* <SP> */, /* 0x20 */
1529
+ /* 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 */
1530
+ /* 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 */
1531
+ /* 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 */
1532
+ /* 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 */
1533
+ /* 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 */
1534
+ /* 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 */
1535
+ /* 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 */
1536
+ };
1537
+
1538
+ static const int String_No_Passthrough[0x100] = {
1539
+ /* 0x00 */ 1 /* <NUL> */, /* 0x00 */
1540
+ /* 0x01 */ 1 /* <SOH> */, /* 0x01 */
1541
+ /* 0x02 */ 1 /* <STX> */, /* 0x02 */
1542
+ /* 0x03 */ 1 /* <ETX> */, /* 0x03 */
1543
+ /* 0x04 */ 1 /* <EOT> */, /* 0x04 */
1544
+ /* 0x05 */ 1 /* <ENQ> */, /* 0x05 */
1545
+ /* 0x06 */ 1 /* <ACK> */, /* 0x06 */
1546
+ /* 0x07 */ 1 /* <BEL> */, /* 0x07 */
1547
+ /* 0x08 */ 1 /* <BS> */, /* 0x08 */
1548
+ /* 0x09 */ 1 /* <HT> */, /* 0x09 */
1549
+ /* 0x0a */ 1 /* <LF> */, /* 0x0a */
1550
+ /* 0x0b */ 1 /* <VT> */, /* 0x0b */
1551
+ /* 0x0c */ 1 /* <FF> */, /* 0x0c */
1552
+ /* 0x0d */ 1 /* <CR> */, /* 0x0d */
1553
+ /* 0x0e */ 1 /* <SO> */, /* 0x0e */
1554
+ /* 0x0f */ 1 /* <SI> */, /* 0x0f */
1555
+ /* 0x10 */ 1 /* <DLE> */, /* 0x10 */
1556
+ /* 0x11 */ 1 /* <DC1> */, /* 0x11 */
1557
+ /* 0x12 */ 1 /* <DC2> */, /* 0x12 */
1558
+ /* 0x13 */ 1 /* <DC3> */, /* 0x13 */
1559
+ /* 0x14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x21 */
1560
+ /* 0x22 */ 1 /* <"> */, /* 0x22 */
1561
+ /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x42 */
1562
+ /* 0x43 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */
1563
+ /* 0x5c */ 1 /* <\> */, /* 0x5c */
1564
+ /* 0x5d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7c */
1565
+ /* 0x7d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9c */
1566
+ /* 0x9d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbc */
1567
+ /* 0xbd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdc */
1568
+ /* 0xdd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfc */
1569
+ /* 0xfd */ 0,0, /* 0xfe */
1570
+ };
1571
+
1572
+ /**
1573
+ * Allowable two-character 'common' escapes:
1574
+ */
1575
+ static int Allowed_Escapes[0x100] = {
1576
+ /* 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 */
1577
+ /* 0x20 */ 0,0, /* 0x21 */
1578
+ /* 0x22 */ 1 /* <"> */, /* 0x22 */
1579
+ /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2e */
1580
+ /* 0x2f */ 1 /* </> */, /* 0x2f */
1581
+ /* 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 */
1582
+ /* 0x50 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */
1583
+ /* 0x5c */ 1 /* <\> */, /* 0x5c */
1584
+ /* 0x5d */ 0,0,0,0,0, /* 0x61 */
1585
+ /* 0x62 */ 1 /* <b> */, /* 0x62 */
1586
+ /* 0x63 */ 0,0,0, /* 0x65 */
1587
+ /* 0x66 */ 1 /* <f> */, /* 0x66 */
1588
+ /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
1589
+ /* 0x6e */ 1 /* <n> */, /* 0x6e */
1590
+ /* 0x6f */ 0,0,0, /* 0x71 */
1591
+ /* 0x72 */ 1 /* <r> */, /* 0x72 */
1592
+ /* 0x73 */ 0, /* 0x73 */
1593
+ /* 0x74 */ 1 /* <t> */, /* 0x74 */
1594
+ /* 0x75 */ 1 /* <u> */, /* 0x75 */
1595
+ /* 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 */
1596
+ /* 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 */
1597
+ /* 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 */
1598
+ /* 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 */
1599
+ /* 0xf6 */ 0,0,0,0,0,0,0,0,0, /* 0xfe */
1600
+ };
1601
+
1602
+ /**
1603
+ * This table contains the _values_ for a given (single) escaped character.
1604
+ */
1605
+ static unsigned char Escape_Equivs[0x100] = {
1606
+ /* 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 */
1607
+ /* 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 */
1608
+ /* 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 */
1609
+ /* 0x60 */ 0,0, /* 0x61 */
1610
+ /* 0x62 */ 8 /* <b> */, /* 0x62 */
1611
+ /* 0x63 */ 0,0,0, /* 0x65 */
1612
+ /* 0x66 */ 12 /* <f> */, /* 0x66 */
1613
+ /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
1614
+ /* 0x6e */ 10 /* <n> */, /* 0x6e */
1615
+ /* 0x6f */ 0,0,0, /* 0x71 */
1616
+ /* 0x72 */ 13 /* <r> */, /* 0x72 */
1617
+ /* 0x73 */ 0, /* 0x73 */
1618
+ /* 0x74 */ 9 /* <t> */, /* 0x74 */
1619
+ /* 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 */
1620
+ /* 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 */
1621
+ /* 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 */
1622
+ /* 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 */
1623
+ /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0 /* 0xfe */
1624
+ };
1625
+
1626
+ /* Definitions of above-declared static functions */
1627
+ static char get_escape_equiv(unsigned c) {
1628
+ return Escape_Equivs[c & 0xff];
1629
+ }
1630
+ static unsigned extract_special(unsigned c) {
1631
+ return Special_Table[c & 0xff];
1632
+ }
1633
+ static int is_special_end(unsigned c) {
1634
+ return Special_Endings[c & 0xff];
1635
+ }
1636
+ static int is_allowed_whitespace(unsigned c) {
1637
+ return c == ' ' || Allowed_Whitespace[c & 0xff];
1638
+ }
1639
+ static int is_allowed_escape(unsigned c) {
1640
+ return Allowed_Escapes[c & 0xff];
1641
+ }
1642
+ static int is_simple_char(unsigned c) {
1643
+ return !String_No_Passthrough[c & 0xff];
1644
+ }
1645
+
1646
+ /* Clean up all our macros! */
1647
+ #undef INCR_METRIC
1648
+ #undef INCR_GENERIC
1649
+ #undef INCR_STRINGY_CATCH
1650
+ #undef CASE_DIGITS
1651
+ #undef INVOKE_ERROR
1652
+ #undef STACK_PUSH
1653
+ #undef STACK_POP_NOPOS
1654
+ #undef STACK_POP
1655
+ #undef CALLBACK_AND_POP_NOPOS
1656
+ #undef CALLBACK_AND_POP
1657
+ #undef SPECIAL_POP
1658
+ #undef CUR_CHAR
1659
+ #undef DO_CALLBACK
1660
+ #undef ENSURE_HVAL
1661
+ #undef VERIFY_SPECIAL
1662
+ #undef STATE_SPECIAL_LENGTH
1663
+ #undef IS_NORMAL_NUMBER
1664
+ #undef STATE_NUM_LAST
1665
+ #undef FASTPARSE_EXHAUSTED
1666
+ #undef FASTPARSE_BREAK