libyajl2 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,117 @@
1
+ /*
2
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3
+ *
4
+ * Permission to use, copy, modify, and/or distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+ #ifndef __YAJL_LEX_H__
18
+ #define __YAJL_LEX_H__
19
+
20
+ #include "api/yajl_common.h"
21
+
22
+ typedef enum {
23
+ yajl_tok_bool,
24
+ yajl_tok_colon,
25
+ yajl_tok_comma,
26
+ yajl_tok_eof,
27
+ yajl_tok_error,
28
+ yajl_tok_left_brace,
29
+ yajl_tok_left_bracket,
30
+ yajl_tok_null,
31
+ yajl_tok_right_brace,
32
+ yajl_tok_right_bracket,
33
+
34
+ /* we differentiate between integers and doubles to allow the
35
+ * parser to interpret the number without re-scanning */
36
+ yajl_tok_integer,
37
+ yajl_tok_double,
38
+
39
+ /* we differentiate between strings which require further processing,
40
+ * and strings that do not */
41
+ yajl_tok_string,
42
+ yajl_tok_string_with_escapes,
43
+
44
+ /* comment tokens are not currently returned to the parser, ever */
45
+ yajl_tok_comment
46
+ } yajl_tok;
47
+
48
+ typedef struct yajl_lexer_t * yajl_lexer;
49
+
50
+ yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc,
51
+ unsigned int allowComments,
52
+ unsigned int validateUTF8);
53
+
54
+ void yajl_lex_free(yajl_lexer lexer);
55
+
56
+ /**
57
+ * run/continue a lex. "offset" is an input/output parameter.
58
+ * It should be initialized to zero for a
59
+ * new chunk of target text, and upon subsetquent calls with the same
60
+ * target text should passed with the value of the previous invocation.
61
+ *
62
+ * the client may be interested in the value of offset when an error is
63
+ * returned from the lexer. This allows the client to render useful
64
+ * error messages.
65
+ *
66
+ * When you pass the next chunk of data, context should be reinitialized
67
+ * to zero.
68
+ *
69
+ * Finally, the output buffer is usually just a pointer into the jsonText,
70
+ * however in cases where the entity being lexed spans multiple chunks,
71
+ * the lexer will buffer the entity and the data returned will be
72
+ * a pointer into that buffer.
73
+ *
74
+ * This behavior is abstracted from client code except for the performance
75
+ * implications which require that the client choose a reasonable chunk
76
+ * size to get adequate performance.
77
+ */
78
+ yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
79
+ size_t jsonTextLen, size_t * offset,
80
+ const unsigned char ** outBuf, size_t * outLen);
81
+
82
+ /** have a peek at the next token, but don't move the lexer forward */
83
+ yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
84
+ size_t jsonTextLen, size_t offset);
85
+
86
+
87
+ typedef enum {
88
+ yajl_lex_e_ok = 0,
89
+ yajl_lex_string_invalid_utf8,
90
+ yajl_lex_string_invalid_escaped_char,
91
+ yajl_lex_string_invalid_json_char,
92
+ yajl_lex_string_invalid_hex_char,
93
+ yajl_lex_invalid_char,
94
+ yajl_lex_invalid_string,
95
+ yajl_lex_missing_integer_after_decimal,
96
+ yajl_lex_missing_integer_after_exponent,
97
+ yajl_lex_missing_integer_after_minus,
98
+ yajl_lex_unallowed_comment
99
+ } yajl_lex_error;
100
+
101
+ const char * yajl_lex_error_to_string(yajl_lex_error error);
102
+
103
+ /** allows access to more specific information about the lexical
104
+ * error when yajl_lex_lex returns yajl_tok_error. */
105
+ yajl_lex_error yajl_lex_get_error(yajl_lexer lexer);
106
+
107
+ /** get the current offset into the most recently lexed json string. */
108
+ size_t yajl_lex_current_offset(yajl_lexer lexer);
109
+
110
+ /** get the number of lines lexed by this lexer instance */
111
+ size_t yajl_lex_current_line(yajl_lexer lexer);
112
+
113
+ /** get the number of chars lexed by this lexer instance since the last
114
+ * \n or \r */
115
+ size_t yajl_lex_current_char(yajl_lexer lexer);
116
+
117
+ #endif
@@ -0,0 +1,498 @@
1
+ /*
2
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3
+ *
4
+ * Permission to use, copy, modify, and/or distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+ #include "api/yajl_parse.h"
18
+ #include "yajl_lex.h"
19
+ #include "yajl_parser.h"
20
+ #include "yajl_encode.h"
21
+ #include "yajl_bytestack.h"
22
+
23
+ #include <stdlib.h>
24
+ #include <limits.h>
25
+ #include <errno.h>
26
+ #include <stdio.h>
27
+ #include <string.h>
28
+ #include <ctype.h>
29
+ #include <assert.h>
30
+ #include <math.h>
31
+
32
+ #define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10))
33
+
34
+ /* same semantics as strtol */
35
+ long long
36
+ yajl_parse_integer(const unsigned char *number, unsigned int length)
37
+ {
38
+ long long ret = 0;
39
+ long sign = 1;
40
+ const unsigned char *pos = number;
41
+ if (*pos == '-') { pos++; sign = -1; }
42
+ if (*pos == '+') { pos++; }
43
+
44
+ while (pos < number + length) {
45
+ if ( ret > MAX_VALUE_TO_MULTIPLY ) {
46
+ errno = ERANGE;
47
+ return sign == 1 ? LLONG_MAX : LLONG_MIN;
48
+ }
49
+ ret *= 10;
50
+ if (LLONG_MAX - ret < (*pos - '0')) {
51
+ errno = ERANGE;
52
+ return sign == 1 ? LLONG_MAX : LLONG_MIN;
53
+ }
54
+ if (*pos < '0' || *pos > '9') {
55
+ errno = ERANGE;
56
+ return sign == 1 ? LLONG_MAX : LLONG_MIN;
57
+ }
58
+ ret += (*pos++ - '0');
59
+ }
60
+
61
+ return sign * ret;
62
+ }
63
+
64
+ unsigned char *
65
+ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
66
+ size_t jsonTextLen, int verbose)
67
+ {
68
+ size_t offset = hand->bytesConsumed;
69
+ unsigned char * str;
70
+ const char * errorType = NULL;
71
+ const char * errorText = NULL;
72
+ char text[72];
73
+ const char * arrow = " (right here) ------^\n";
74
+
75
+ if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) {
76
+ errorType = "parse";
77
+ errorText = hand->parseError;
78
+ } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) {
79
+ errorType = "lexical";
80
+ errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer));
81
+ } else {
82
+ errorType = "unknown";
83
+ }
84
+
85
+ {
86
+ size_t memneeded = 0;
87
+ memneeded += strlen(errorType);
88
+ memneeded += strlen(" error");
89
+ if (errorText != NULL) {
90
+ memneeded += strlen(": ");
91
+ memneeded += strlen(errorText);
92
+ }
93
+ str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2);
94
+ if (!str) return NULL;
95
+ str[0] = 0;
96
+ strcat((char *) str, errorType);
97
+ strcat((char *) str, " error");
98
+ if (errorText != NULL) {
99
+ strcat((char *) str, ": ");
100
+ strcat((char *) str, errorText);
101
+ }
102
+ strcat((char *) str, "\n");
103
+ }
104
+
105
+ /* now we append as many spaces as needed to make sure the error
106
+ * falls at char 41, if verbose was specified */
107
+ if (verbose) {
108
+ size_t start, end, i;
109
+ size_t spacesNeeded;
110
+
111
+ spacesNeeded = (offset < 30 ? 40 - offset : 10);
112
+ start = (offset >= 30 ? offset - 30 : 0);
113
+ end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30);
114
+
115
+ for (i=0;i<spacesNeeded;i++) text[i] = ' ';
116
+
117
+ for (;start < end;start++, i++) {
118
+ if (jsonText[start] != '\n' && jsonText[start] != '\r')
119
+ {
120
+ text[i] = jsonText[start];
121
+ }
122
+ else
123
+ {
124
+ text[i] = ' ';
125
+ }
126
+ }
127
+ assert(i <= 71);
128
+ text[i++] = '\n';
129
+ text[i] = 0;
130
+ {
131
+ char * newStr = (char *)
132
+ YA_MALLOC(&(hand->alloc), (unsigned int)(strlen((char *) str) +
133
+ strlen((char *) text) +
134
+ strlen(arrow) + 1));
135
+ if (newStr) {
136
+ newStr[0] = 0;
137
+ strcat((char *) newStr, (char *) str);
138
+ strcat((char *) newStr, text);
139
+ strcat((char *) newStr, arrow);
140
+ }
141
+ YA_FREE(&(hand->alloc), str);
142
+ str = (unsigned char *) newStr;
143
+ }
144
+ }
145
+ return str;
146
+ }
147
+
148
+ /* check for client cancelation */
149
+ #define _CC_CHK(x) \
150
+ if (!(x)) { \
151
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
152
+ hand->parseError = \
153
+ "client cancelled parse via callback return value"; \
154
+ return yajl_status_client_canceled; \
155
+ }
156
+
157
+
158
+ yajl_status
159
+ yajl_do_finish(yajl_handle hand)
160
+ {
161
+ yajl_status stat;
162
+ stat = yajl_do_parse(hand,(const unsigned char *) " ",1);
163
+
164
+ if (stat != yajl_status_ok) return stat;
165
+
166
+ switch(yajl_bs_current(hand->stateStack))
167
+ {
168
+ case yajl_state_parse_error:
169
+ case yajl_state_lexical_error:
170
+ return yajl_status_error;
171
+ case yajl_state_got_value:
172
+ case yajl_state_parse_complete:
173
+ return yajl_status_ok;
174
+ default:
175
+ if (!(hand->flags & yajl_allow_partial_values))
176
+ {
177
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
178
+ hand->parseError = "premature EOF";
179
+ return yajl_status_error;
180
+ }
181
+ return yajl_status_ok;
182
+ }
183
+ }
184
+
185
+ yajl_status
186
+ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
187
+ size_t jsonTextLen)
188
+ {
189
+ yajl_tok tok;
190
+ const unsigned char * buf;
191
+ size_t bufLen;
192
+ size_t * offset = &(hand->bytesConsumed);
193
+
194
+ *offset = 0;
195
+
196
+ around_again:
197
+ switch (yajl_bs_current(hand->stateStack)) {
198
+ case yajl_state_parse_complete:
199
+ if (hand->flags & yajl_allow_multiple_values) {
200
+ yajl_bs_set(hand->stateStack, yajl_state_got_value);
201
+ goto around_again;
202
+ }
203
+ if (!(hand->flags & yajl_allow_trailing_garbage)) {
204
+ if (*offset != jsonTextLen) {
205
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
206
+ offset, &buf, &bufLen);
207
+ if (tok != yajl_tok_eof) {
208
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
209
+ hand->parseError = "trailing garbage";
210
+ }
211
+ goto around_again;
212
+ }
213
+ }
214
+ return yajl_status_ok;
215
+ case yajl_state_lexical_error:
216
+ case yajl_state_parse_error:
217
+ return yajl_status_error;
218
+ case yajl_state_start:
219
+ case yajl_state_got_value:
220
+ case yajl_state_map_need_val:
221
+ case yajl_state_array_need_val:
222
+ case yajl_state_array_start: {
223
+ /* for arrays and maps, we advance the state for this
224
+ * depth, then push the state of the next depth.
225
+ * If an error occurs during the parsing of the nesting
226
+ * enitity, the state at this level will not matter.
227
+ * a state that needs pushing will be anything other
228
+ * than state_start */
229
+
230
+ yajl_state stateToPush = yajl_state_start;
231
+
232
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
233
+ offset, &buf, &bufLen);
234
+
235
+ switch (tok) {
236
+ case yajl_tok_eof:
237
+ return yajl_status_ok;
238
+ case yajl_tok_error:
239
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
240
+ goto around_again;
241
+ case yajl_tok_string:
242
+ if (hand->callbacks && hand->callbacks->yajl_string) {
243
+ _CC_CHK(hand->callbacks->yajl_string(hand->ctx,
244
+ buf, bufLen));
245
+ }
246
+ break;
247
+ case yajl_tok_string_with_escapes:
248
+ if (hand->callbacks && hand->callbacks->yajl_string) {
249
+ yajl_buf_clear(hand->decodeBuf);
250
+ yajl_string_decode(hand->decodeBuf, buf, bufLen);
251
+ _CC_CHK(hand->callbacks->yajl_string(
252
+ hand->ctx, yajl_buf_data(hand->decodeBuf),
253
+ yajl_buf_len(hand->decodeBuf)));
254
+ }
255
+ break;
256
+ case yajl_tok_bool:
257
+ if (hand->callbacks && hand->callbacks->yajl_boolean) {
258
+ _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx,
259
+ *buf == 't'));
260
+ }
261
+ break;
262
+ case yajl_tok_null:
263
+ if (hand->callbacks && hand->callbacks->yajl_null) {
264
+ _CC_CHK(hand->callbacks->yajl_null(hand->ctx));
265
+ }
266
+ break;
267
+ case yajl_tok_left_bracket:
268
+ if (hand->callbacks && hand->callbacks->yajl_start_map) {
269
+ _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
270
+ }
271
+ stateToPush = yajl_state_map_start;
272
+ break;
273
+ case yajl_tok_left_brace:
274
+ if (hand->callbacks && hand->callbacks->yajl_start_array) {
275
+ _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
276
+ }
277
+ stateToPush = yajl_state_array_start;
278
+ break;
279
+ case yajl_tok_integer:
280
+ if (hand->callbacks) {
281
+ if (hand->callbacks->yajl_number) {
282
+ _CC_CHK(hand->callbacks->yajl_number(
283
+ hand->ctx,(const char *) buf, bufLen));
284
+ } else if (hand->callbacks->yajl_integer) {
285
+ long long int i = 0;
286
+ errno = 0;
287
+ i = yajl_parse_integer(buf, bufLen);
288
+ if ((i == LLONG_MIN || i == LLONG_MAX) &&
289
+ errno == ERANGE)
290
+ {
291
+ yajl_bs_set(hand->stateStack,
292
+ yajl_state_parse_error);
293
+ hand->parseError = "integer overflow" ;
294
+ /* try to restore error offset */
295
+ if (*offset >= bufLen) *offset -= bufLen;
296
+ else *offset = 0;
297
+ goto around_again;
298
+ }
299
+ _CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
300
+ i));
301
+ }
302
+ }
303
+ break;
304
+ case yajl_tok_double:
305
+ if (hand->callbacks) {
306
+ if (hand->callbacks->yajl_number) {
307
+ _CC_CHK(hand->callbacks->yajl_number(
308
+ hand->ctx, (const char *) buf, bufLen));
309
+ } else if (hand->callbacks->yajl_double) {
310
+ double d = 0.0;
311
+ yajl_buf_clear(hand->decodeBuf);
312
+ yajl_buf_append(hand->decodeBuf, buf, bufLen);
313
+ buf = yajl_buf_data(hand->decodeBuf);
314
+ errno = 0;
315
+ d = strtod((char *) buf, NULL);
316
+ if ((d == HUGE_VAL || d == -HUGE_VAL) &&
317
+ errno == ERANGE)
318
+ {
319
+ yajl_bs_set(hand->stateStack,
320
+ yajl_state_parse_error);
321
+ hand->parseError = "numeric (floating point) "
322
+ "overflow";
323
+ /* try to restore error offset */
324
+ if (*offset >= bufLen) *offset -= bufLen;
325
+ else *offset = 0;
326
+ goto around_again;
327
+ }
328
+ _CC_CHK(hand->callbacks->yajl_double(hand->ctx,
329
+ d));
330
+ }
331
+ }
332
+ break;
333
+ case yajl_tok_right_brace: {
334
+ if (yajl_bs_current(hand->stateStack) ==
335
+ yajl_state_array_start)
336
+ {
337
+ if (hand->callbacks &&
338
+ hand->callbacks->yajl_end_array)
339
+ {
340
+ _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
341
+ }
342
+ yajl_bs_pop(hand->stateStack);
343
+ goto around_again;
344
+ }
345
+ /* intentional fall-through */
346
+ }
347
+ case yajl_tok_colon:
348
+ case yajl_tok_comma:
349
+ case yajl_tok_right_bracket:
350
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
351
+ hand->parseError =
352
+ "unallowed token at this point in JSON text";
353
+ goto around_again;
354
+ default:
355
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
356
+ hand->parseError = "invalid token, internal error";
357
+ goto around_again;
358
+ }
359
+ /* got a value. transition depends on the state we're in. */
360
+ {
361
+ yajl_state s = yajl_bs_current(hand->stateStack);
362
+ if (s == yajl_state_start || s == yajl_state_got_value) {
363
+ yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
364
+ } else if (s == yajl_state_map_need_val) {
365
+ yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
366
+ } else {
367
+ yajl_bs_set(hand->stateStack, yajl_state_array_got_val);
368
+ }
369
+ }
370
+ if (stateToPush != yajl_state_start) {
371
+ yajl_bs_push(hand->stateStack, stateToPush);
372
+ }
373
+
374
+ goto around_again;
375
+ }
376
+ case yajl_state_map_start:
377
+ case yajl_state_map_need_key: {
378
+ /* only difference between these two states is that in
379
+ * start '}' is valid, whereas in need_key, we've parsed
380
+ * a comma, and a string key _must_ follow */
381
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
382
+ offset, &buf, &bufLen);
383
+ switch (tok) {
384
+ case yajl_tok_eof:
385
+ return yajl_status_ok;
386
+ case yajl_tok_error:
387
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
388
+ goto around_again;
389
+ case yajl_tok_string_with_escapes:
390
+ if (hand->callbacks && hand->callbacks->yajl_map_key) {
391
+ yajl_buf_clear(hand->decodeBuf);
392
+ yajl_string_decode(hand->decodeBuf, buf, bufLen);
393
+ buf = yajl_buf_data(hand->decodeBuf);
394
+ bufLen = yajl_buf_len(hand->decodeBuf);
395
+ }
396
+ /* intentional fall-through */
397
+ case yajl_tok_string:
398
+ if (hand->callbacks && hand->callbacks->yajl_map_key) {
399
+ _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf,
400
+ bufLen));
401
+ }
402
+ yajl_bs_set(hand->stateStack, yajl_state_map_sep);
403
+ goto around_again;
404
+ case yajl_tok_right_bracket:
405
+ if (yajl_bs_current(hand->stateStack) ==
406
+ yajl_state_map_start)
407
+ {
408
+ if (hand->callbacks && hand->callbacks->yajl_end_map) {
409
+ _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
410
+ }
411
+ yajl_bs_pop(hand->stateStack);
412
+ goto around_again;
413
+ }
414
+ default:
415
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
416
+ hand->parseError =
417
+ "invalid object key (must be a string)";
418
+ goto around_again;
419
+ }
420
+ }
421
+ case yajl_state_map_sep: {
422
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
423
+ offset, &buf, &bufLen);
424
+ switch (tok) {
425
+ case yajl_tok_colon:
426
+ yajl_bs_set(hand->stateStack, yajl_state_map_need_val);
427
+ goto around_again;
428
+ case yajl_tok_eof:
429
+ return yajl_status_ok;
430
+ case yajl_tok_error:
431
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
432
+ goto around_again;
433
+ default:
434
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
435
+ hand->parseError = "object key and value must "
436
+ "be separated by a colon (':')";
437
+ goto around_again;
438
+ }
439
+ }
440
+ case yajl_state_map_got_val: {
441
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
442
+ offset, &buf, &bufLen);
443
+ switch (tok) {
444
+ case yajl_tok_right_bracket:
445
+ if (hand->callbacks && hand->callbacks->yajl_end_map) {
446
+ _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
447
+ }
448
+ yajl_bs_pop(hand->stateStack);
449
+ goto around_again;
450
+ case yajl_tok_comma:
451
+ yajl_bs_set(hand->stateStack, yajl_state_map_need_key);
452
+ goto around_again;
453
+ case yajl_tok_eof:
454
+ return yajl_status_ok;
455
+ case yajl_tok_error:
456
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
457
+ goto around_again;
458
+ default:
459
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
460
+ hand->parseError = "after key and value, inside map, "
461
+ "I expect ',' or '}'";
462
+ /* try to restore error offset */
463
+ if (*offset >= bufLen) *offset -= bufLen;
464
+ else *offset = 0;
465
+ goto around_again;
466
+ }
467
+ }
468
+ case yajl_state_array_got_val: {
469
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
470
+ offset, &buf, &bufLen);
471
+ switch (tok) {
472
+ case yajl_tok_right_brace:
473
+ if (hand->callbacks && hand->callbacks->yajl_end_array) {
474
+ _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
475
+ }
476
+ yajl_bs_pop(hand->stateStack);
477
+ goto around_again;
478
+ case yajl_tok_comma:
479
+ yajl_bs_set(hand->stateStack, yajl_state_array_need_val);
480
+ goto around_again;
481
+ case yajl_tok_eof:
482
+ return yajl_status_ok;
483
+ case yajl_tok_error:
484
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
485
+ goto around_again;
486
+ default:
487
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
488
+ hand->parseError =
489
+ "after array element, I expect ',' or ']'";
490
+ goto around_again;
491
+ }
492
+ }
493
+ }
494
+
495
+ abort();
496
+ return yajl_status_error;
497
+ }
498
+
@@ -0,0 +1,78 @@
1
+ /*
2
+ * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3
+ *
4
+ * Permission to use, copy, modify, and/or distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+
17
+ #ifndef __YAJL_PARSER_H__
18
+ #define __YAJL_PARSER_H__
19
+
20
+ #include "api/yajl_parse.h"
21
+ #include "yajl_bytestack.h"
22
+ #include "yajl_buf.h"
23
+ #include "yajl_lex.h"
24
+
25
+
26
+ typedef enum {
27
+ yajl_state_start = 0,
28
+ yajl_state_parse_complete,
29
+ yajl_state_parse_error,
30
+ yajl_state_lexical_error,
31
+ yajl_state_map_start,
32
+ yajl_state_map_sep,
33
+ yajl_state_map_need_val,
34
+ yajl_state_map_got_val,
35
+ yajl_state_map_need_key,
36
+ yajl_state_array_start,
37
+ yajl_state_array_got_val,
38
+ yajl_state_array_need_val,
39
+ yajl_state_got_value,
40
+ } yajl_state;
41
+
42
+ struct yajl_handle_t {
43
+ const yajl_callbacks * callbacks;
44
+ void * ctx;
45
+ yajl_lexer lexer;
46
+ const char * parseError;
47
+ /* the number of bytes consumed from the last client buffer,
48
+ * in the case of an error this will be an error offset, in the
49
+ * case of an error this can be used as the error offset */
50
+ size_t bytesConsumed;
51
+ /* temporary storage for decoded strings */
52
+ yajl_buf decodeBuf;
53
+ /* a stack of states. access with yajl_state_XXX routines */
54
+ yajl_bytestack stateStack;
55
+ /* memory allocation routines */
56
+ yajl_alloc_funcs alloc;
57
+ /* bitfield */
58
+ unsigned int flags;
59
+ };
60
+
61
+ yajl_status
62
+ yajl_do_parse(yajl_handle handle, const unsigned char * jsonText,
63
+ size_t jsonTextLen);
64
+
65
+ yajl_status
66
+ yajl_do_finish(yajl_handle handle);
67
+
68
+ unsigned char *
69
+ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
70
+ size_t jsonTextLen, int verbose);
71
+
72
+ /* A little built in integer parsing routine with the same semantics as strtol
73
+ * that's unaffected by LOCALE. */
74
+ long long
75
+ yajl_parse_integer(const unsigned char *number, unsigned int length);
76
+
77
+
78
+ #endif