2 * Copyright 2007-2009, Lloyd Hilaiel.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * 3. Neither the name of Lloyd Hilaiel nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 #include "yajl_parser.h"
35 #include "yajl_encode.h"
36 #include "yajl_bytestack.h"
48 yajl_render_error_string(yajl_handle hand
, const unsigned char * jsonText
,
49 unsigned int jsonTextLen
, int verbose
)
51 unsigned int offset
= hand
->errorOffset
;
53 const char * errorType
= NULL
;
54 const char * errorText
= NULL
;
56 const char * arrow
= " (right here) ------^\n";
58 if (yajl_bs_current(hand
->stateStack
) == yajl_state_parse_error
) {
60 errorText
= hand
->parseError
;
61 } else if (yajl_bs_current(hand
->stateStack
) == yajl_state_lexical_error
) {
62 errorType
= "lexical";
63 errorText
= yajl_lex_error_to_string(yajl_lex_get_error(hand
->lexer
));
65 errorType
= "unknown";
69 unsigned int memneeded
= 0;
70 memneeded
+= strlen(errorType
);
71 memneeded
+= strlen(" error");
72 if (errorText
!= NULL
) {
73 memneeded
+= strlen(": ");
74 memneeded
+= strlen(errorText
);
76 str
= (unsigned char *) YA_MALLOC(&(hand
->alloc
), memneeded
+ 2);
78 strcat((char *) str
, errorType
);
79 strcat((char *) str
, " error");
80 if (errorText
!= NULL
) {
81 strcat((char *) str
, ": ");
82 strcat((char *) str
, errorText
);
84 strcat((char *) str
, "\n");
87 /* now we append as many spaces as needed to make sure the error
88 * falls at char 41, if verbose was specified */
90 unsigned int start
, end
, i
;
91 unsigned int spacesNeeded
;
93 spacesNeeded
= (offset
< 30 ? 40 - offset
: 10);
94 start
= (offset
>= 30 ? offset
- 30 : 0);
95 end
= (offset
+ 30 > jsonTextLen
? jsonTextLen
: offset
+ 30);
97 for (i
=0;i
<spacesNeeded
;i
++) text
[i
] = ' ';
99 for (;start
< end
;start
++, i
++) {
100 if (jsonText
[start
] != '\n' && jsonText
[start
] != '\r')
102 text
[i
] = jsonText
[start
];
113 char * newStr
= (char *)
114 YA_MALLOC(&(hand
->alloc
), (strlen((char *) str
) +
115 strlen((char *) text
) +
118 strcat((char *) newStr
, (char *) str
);
119 strcat((char *) newStr
, text
);
120 strcat((char *) newStr
, arrow
);
121 YA_FREE(&(hand
->alloc
), str
);
122 str
= (unsigned char *) newStr
;
128 /* check for client cancelation */
131 yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
133 "client cancelled parse via callback return value"; \
134 return yajl_status_client_canceled; \
139 yajl_do_parse(yajl_handle hand
, unsigned int * offset
,
140 const unsigned char * jsonText
, unsigned int jsonTextLen
)
143 const unsigned char * buf
;
147 switch (yajl_bs_current(hand
->stateStack
)) {
148 case yajl_state_parse_complete
:
149 return yajl_status_ok
;
150 case yajl_state_lexical_error
:
151 case yajl_state_parse_error
:
152 hand
->errorOffset
= *offset
;
153 return yajl_status_error
;
154 case yajl_state_start
:
155 case yajl_state_map_need_val
:
156 case yajl_state_array_need_val
:
157 case yajl_state_array_start
: {
158 /* for arrays and maps, we advance the state for this
159 * depth, then push the state of the next depth.
160 * If an error occurs during the parsing of the nesting
161 * enitity, the state at this level will not matter.
162 * a state that needs pushing will be anything other
163 * than state_start */
164 yajl_state stateToPush
= yajl_state_start
;
166 tok
= yajl_lex_lex(hand
->lexer
, jsonText
, jsonTextLen
,
167 offset
, &buf
, &bufLen
);
171 return yajl_status_insufficient_data
;
173 yajl_bs_set(hand
->stateStack
, yajl_state_lexical_error
);
175 case yajl_tok_string
:
176 if (hand
->callbacks
&& hand
->callbacks
->yajl_string
) {
177 _CC_CHK(hand
->callbacks
->yajl_string(hand
->ctx
,
181 case yajl_tok_string_with_escapes
:
182 if (hand
->callbacks
&& hand
->callbacks
->yajl_string
) {
183 yajl_buf_clear(hand
->decodeBuf
);
184 yajl_string_decode(hand
->decodeBuf
, buf
, bufLen
);
185 _CC_CHK(hand
->callbacks
->yajl_string(
186 hand
->ctx
, yajl_buf_data(hand
->decodeBuf
),
187 yajl_buf_len(hand
->decodeBuf
)));
191 if (hand
->callbacks
&& hand
->callbacks
->yajl_boolean
) {
192 _CC_CHK(hand
->callbacks
->yajl_boolean(hand
->ctx
,
197 if (hand
->callbacks
&& hand
->callbacks
->yajl_null
) {
198 _CC_CHK(hand
->callbacks
->yajl_null(hand
->ctx
));
201 case yajl_tok_left_bracket
:
202 if (hand
->callbacks
&& hand
->callbacks
->yajl_start_map
) {
203 _CC_CHK(hand
->callbacks
->yajl_start_map(hand
->ctx
));
205 stateToPush
= yajl_state_map_start
;
207 case yajl_tok_left_brace
:
208 if (hand
->callbacks
&& hand
->callbacks
->yajl_start_array
) {
209 _CC_CHK(hand
->callbacks
->yajl_start_array(hand
->ctx
));
211 stateToPush
= yajl_state_array_start
;
213 case yajl_tok_integer
:
215 * note. strtol does not respect the length of
216 * the lexical token. in a corner case where the
217 * lexed number is a integer with a trailing zero,
218 * immediately followed by the end of buffer,
219 * sscanf could run off into oblivion and cause a
220 * crash. for this reason we copy the integer
221 * (and doubles), into our parse buffer (the same
222 * one used for unescaping strings), before
223 * calling strtol. yajl_buf ensures null padding,
226 if (hand
->callbacks
) {
227 if (hand
->callbacks
->yajl_number
) {
228 _CC_CHK(hand
->callbacks
->yajl_number(
229 hand
->ctx
,(const char *) buf
, bufLen
));
230 } else if (hand
->callbacks
->yajl_integer
) {
232 yajl_buf_clear(hand
->decodeBuf
);
233 yajl_buf_append(hand
->decodeBuf
, buf
, bufLen
);
234 buf
= yajl_buf_data(hand
->decodeBuf
);
235 i
= strtol((const char *) buf
, NULL
, 10);
236 if ((i
== LONG_MIN
|| i
== LONG_MAX
) &&
239 yajl_bs_set(hand
->stateStack
,
240 yajl_state_parse_error
);
241 hand
->parseError
= "integer overflow" ;
242 /* try to restore error offset */
243 if (*offset
>= bufLen
) *offset
-= bufLen
;
247 _CC_CHK(hand
->callbacks
->yajl_integer(hand
->ctx
,
252 case yajl_tok_double
:
253 if (hand
->callbacks
) {
254 if (hand
->callbacks
->yajl_number
) {
255 _CC_CHK(hand
->callbacks
->yajl_number(
256 hand
->ctx
, (const char *) buf
, bufLen
));
257 } else if (hand
->callbacks
->yajl_double
) {
259 yajl_buf_clear(hand
->decodeBuf
);
260 yajl_buf_append(hand
->decodeBuf
, buf
, bufLen
);
261 buf
= yajl_buf_data(hand
->decodeBuf
);
262 d
= strtod((char *) buf
, NULL
);
263 if ((d
== HUGE_VAL
|| d
== -HUGE_VAL
) &&
266 yajl_bs_set(hand
->stateStack
,
267 yajl_state_parse_error
);
268 hand
->parseError
= "numeric (floating point) "
270 /* try to restore error offset */
271 if (*offset
>= bufLen
) *offset
-= bufLen
;
275 _CC_CHK(hand
->callbacks
->yajl_double(hand
->ctx
,
280 case yajl_tok_right_brace
: {
281 if (yajl_bs_current(hand
->stateStack
) ==
282 yajl_state_array_start
)
284 if (hand
->callbacks
&&
285 hand
->callbacks
->yajl_end_array
)
287 _CC_CHK(hand
->callbacks
->yajl_end_array(hand
->ctx
));
289 yajl_bs_pop(hand
->stateStack
);
292 /* intentional fall-through */
296 case yajl_tok_right_bracket
:
297 yajl_bs_set(hand
->stateStack
, yajl_state_parse_error
);
299 "unallowed token at this point in JSON text";
302 yajl_bs_set(hand
->stateStack
, yajl_state_parse_error
);
303 hand
->parseError
= "invalid token, internal error";
306 /* got a value. transition depends on the state we're in. */
308 yajl_state s
= yajl_bs_current(hand
->stateStack
);
309 if (s
== yajl_state_start
) {
310 yajl_bs_set(hand
->stateStack
, yajl_state_parse_complete
);
311 } else if (s
== yajl_state_map_need_val
) {
312 yajl_bs_set(hand
->stateStack
, yajl_state_map_got_val
);
314 yajl_bs_set(hand
->stateStack
, yajl_state_array_got_val
);
317 if (stateToPush
!= yajl_state_start
) {
318 yajl_bs_push(hand
->stateStack
, stateToPush
);
323 case yajl_state_map_start
:
324 case yajl_state_map_need_key
: {
325 /* only difference between these two states is that in
326 * start '}' is valid, whereas in need_key, we've parsed
327 * a comma, and a string key _must_ follow */
328 tok
= yajl_lex_lex(hand
->lexer
, jsonText
, jsonTextLen
,
329 offset
, &buf
, &bufLen
);
332 return yajl_status_insufficient_data
;
334 yajl_bs_set(hand
->stateStack
, yajl_state_lexical_error
);
336 case yajl_tok_string_with_escapes
:
337 if (hand
->callbacks
&& hand
->callbacks
->yajl_map_key
) {
338 yajl_buf_clear(hand
->decodeBuf
);
339 yajl_string_decode(hand
->decodeBuf
, buf
, bufLen
);
340 buf
= yajl_buf_data(hand
->decodeBuf
);
341 bufLen
= yajl_buf_len(hand
->decodeBuf
);
343 /* intentional fall-through */
344 case yajl_tok_string
:
345 if (hand
->callbacks
&& hand
->callbacks
->yajl_map_key
) {
346 _CC_CHK(hand
->callbacks
->yajl_map_key(hand
->ctx
, buf
,
349 yajl_bs_set(hand
->stateStack
, yajl_state_map_sep
);
351 case yajl_tok_right_bracket
:
352 if (yajl_bs_current(hand
->stateStack
) ==
353 yajl_state_map_start
)
355 if (hand
->callbacks
&& hand
->callbacks
->yajl_end_map
) {
356 _CC_CHK(hand
->callbacks
->yajl_end_map(hand
->ctx
));
358 yajl_bs_pop(hand
->stateStack
);
362 yajl_bs_set(hand
->stateStack
, yajl_state_parse_error
);
364 "invalid object key (must be a string)";
368 case yajl_state_map_sep
: {
369 tok
= yajl_lex_lex(hand
->lexer
, jsonText
, jsonTextLen
,
370 offset
, &buf
, &bufLen
);
373 yajl_bs_set(hand
->stateStack
, yajl_state_map_need_val
);
376 return yajl_status_insufficient_data
;
378 yajl_bs_set(hand
->stateStack
, yajl_state_lexical_error
);
381 yajl_bs_set(hand
->stateStack
, yajl_state_parse_error
);
382 hand
->parseError
= "object key and value must "
383 "be separated by a colon (':')";
387 case yajl_state_map_got_val
: {
388 tok
= yajl_lex_lex(hand
->lexer
, jsonText
, jsonTextLen
,
389 offset
, &buf
, &bufLen
);
391 case yajl_tok_right_bracket
:
392 if (hand
->callbacks
&& hand
->callbacks
->yajl_end_map
) {
393 _CC_CHK(hand
->callbacks
->yajl_end_map(hand
->ctx
));
395 yajl_bs_pop(hand
->stateStack
);
398 yajl_bs_set(hand
->stateStack
, yajl_state_map_need_key
);
401 return yajl_status_insufficient_data
;
403 yajl_bs_set(hand
->stateStack
, yajl_state_lexical_error
);
406 yajl_bs_set(hand
->stateStack
, yajl_state_parse_error
);
407 hand
->parseError
= "after key and value, inside map, "
408 "I expect ',' or '}'";
409 /* try to restore error offset */
410 if (*offset
>= bufLen
) *offset
-= bufLen
;
415 case yajl_state_array_got_val
: {
416 tok
= yajl_lex_lex(hand
->lexer
, jsonText
, jsonTextLen
,
417 offset
, &buf
, &bufLen
);
419 case yajl_tok_right_brace
:
420 if (hand
->callbacks
&& hand
->callbacks
->yajl_end_array
) {
421 _CC_CHK(hand
->callbacks
->yajl_end_array(hand
->ctx
));
423 yajl_bs_pop(hand
->stateStack
);
426 yajl_bs_set(hand
->stateStack
, yajl_state_array_need_val
);
429 return yajl_status_insufficient_data
;
431 yajl_bs_set(hand
->stateStack
, yajl_state_lexical_error
);
434 yajl_bs_set(hand
->stateStack
, yajl_state_parse_error
);
436 "after array element, I expect ',' or ']'";
443 return yajl_status_error
;