File Coverage

json-entry-points.c
Criterion Covered Total %
statement 135 159 84.9
branch 24 34 70.5
condition n/a
subroutine n/a
pod n/a
total 159 193 82.3


line stmt bran cond sub pod time code
1             /* Empty input was provided. */
2              
3 4           static void fail_empty (json_parse_t * parser)
4             {
5 4           parser->bad_type = json_initial_state;
6 4           parser->expected = 0;
7 4           parser->error = json_error_empty_input;
8 4           failbadinput (parser);
9             }
10              
11             /* Check for stray non-whitespace after the end and free memory. */
12              
13 129           static void check_end (json_parse_t * parser)
14             {
15             int c;
16             end:
17 155           switch (NEXTBYTE) {
18              
19 20           case WHITESPACE:
20 26           goto end;
21              
22             case '\0':
23 124           parser_free (parser);
24 124           return;
25              
26             default:
27 5           parser->bad_type = json_initial_state;
28 5           parser->bad_byte = parser->end - 1;
29 5           parser->expected = XWHITESPACE;
30 5           parser->error = json_error_unexpected_character;
31 5           failbadinput (parser);
32             }
33             }
34              
35             #define ENTRYDECL \
36             /* Our collection of bits and pieces. */ \
37             \
38             json_parse_t parser_o = {0}; \
39             json_parse_t * parser = & parser_o; \
40             json_parse_init (parser)
41              
42             #ifndef NOPERL
43              
44             /* Set up "parser" with the string from "json". */
45              
46 305           static void getstring (SV * json, json_parse_t * parser)
47             {
48             STRLEN length;
49 305 100         parser->input = (unsigned char *) SvPV (json, length);
50 305           parser->end = parser->input;
51 305           parser->length = (unsigned int) length;
52 305           parser->unicode = SvUTF8 (json) ? 1 : 0;
53 305           }
54              
55             #endif /* ndef NOPERL */
56              
57             #define SETUPPARSER \
58             parser->line = 1; \
59             parser->last_byte = parser->input + parser->length
60              
61             /* Error to throw if there is a character other than whitespace, "["
62             or "{" at the start of the JSON. */
63              
64             #define BADCHAR \
65             parser->bad_byte = parser->end - 1; \
66             parser->bad_type = json_initial_state; \
67             parser->expected = XARRAYOBJECTSTART | VALUE_START | XWHITESPACE; \
68             parser->error = json_error_unexpected_character; \
69             failbadinput (parser)
70              
71             #ifndef NOPERL
72              
73             static SV *
74 80           json_parse_run (json_parse_t * parser, SV * json)
75             {
76             /* The currently-parsed character. */
77            
78             char c;
79            
80             /* The returned object. */
81              
82 80           SV * r = & PL_sv_undef;
83              
84 80           getstring (json, parser);
85              
86 80 100         if (parser->length == 0) {
87 2           fail_empty (parser);
88             }
89              
90 78           SETUPPARSER;
91              
92             parse_start:
93              
94 86           switch (NEXTBYTE) {
95              
96             case '{':
97 44 50         INCDEPTH;
98 44           r = object (parser);
99 39           break;
100              
101             case '[':
102 22 50         INCDEPTH;
103 22           r = array (parser);
104 19           break;
105              
106             case '-':
107             case '0':
108             case DIGIT19:
109 2           parser->top_level_value = 1;
110 2           r = number (parser);
111 2           break;
112              
113             case '"':
114 5           parser->top_level_value = 1;
115 5           r = string (parser);
116 5           break;
117              
118             case 't':
119 2           parser->top_level_value = 1;
120 2           r = literal_true (parser);
121 1           break;
122              
123             case 'f':
124 0           parser->top_level_value = 1;
125 0           r = literal_false (parser);
126 0           break;
127              
128             case 'n':
129 1           parser->top_level_value = 1;
130 1           r = literal_null (parser);
131 1           break;
132              
133 1           case WHITESPACE:
134 8           goto parse_start;
135              
136             case '\0':
137              
138             /* We have an empty string. */
139              
140 1           fail_empty (parser);
141              
142             default:
143 1           BADCHAR;
144             }
145              
146 67           check_end (parser);
147              
148 66           return r;
149             }
150              
151             /* This is the entry point for non-object parsing. */
152              
153             SV *
154 55           parse (SV * json)
155             {
156             /* Make our own parser object on the stack. */
157 55           ENTRYDECL;
158             /* Run it. */
159 55           return json_parse_run (parser, json);
160             }
161              
162              
163             /* This is the entry point for "safe" non-object parsing. */
164              
165             SV *
166 4           parse_safe (SV * json)
167             {
168             /* Make our own parser object on the stack. */
169 4           ENTRYDECL;
170 4           parser_o.detect_collisions = 1;
171 4           parser_o.copy_literals = 1;
172 4           parser_o.warn_only = 1;
173 4           parser_o.diagnostics_hash = 1;
174             /* Run it. */
175 4           return json_parse_run (parser, json);
176             }
177              
178              
179             #endif /* ndef NOPERL */
180              
181             /* Validation without Perl structures. */
182              
183             static void
184 220           c_validate (json_parse_t * parser)
185             {
186             /* The currently-parsed character. */
187            
188             char c;
189              
190             /* If the string is empty, throw an exception. */
191              
192 220 50         if (parser->length == 0) {
193 0           fail_empty (parser);
194             }
195              
196 220           SETUPPARSER;
197              
198             validate_start:
199              
200 231           switch (NEXTBYTE) {
201              
202             case '{':
203 42 50         INCDEPTH;
204 42           valid_object (parser);
205 17           break;
206              
207             case '[':
208 90 50         INCDEPTH;
209 90           valid_array (parser);
210 33           break;
211              
212             case '-':
213             case '0':
214             case DIGIT19:
215 3           parser->top_level_value = 1;
216 3           valid_number (parser);
217 3           break;
218              
219             case '"':
220 3           parser->top_level_value = 1;
221 3           valid_string (parser);
222 3           break;
223              
224             case 't':
225 2           parser->top_level_value = 1;
226 2           valid_literal_true (parser);
227 1           break;
228              
229             case 'f':
230 0           parser->top_level_value = 1;
231 0           valid_literal_false (parser);
232 0           break;
233              
234             case 'n':
235 1           parser->top_level_value = 1;
236 1           valid_literal_null (parser);
237 1           break;
238              
239 2           case WHITESPACE:
240 11           goto validate_start;
241              
242             default:
243 79           BADCHAR;
244             }
245              
246 58           check_end (parser);
247 54           }
248              
249             static INLINE void
250             print_tokens (json_token_t * t)
251             {
252             printf ("Start: %d End: %d: Type: %s\n", t->start, t->end,
253             token_names[t->type]);
254             if (t->child) {
255             printf ("Children:\n");
256             print_tokens (t->child);
257             }
258             if (t->next) {
259             printf ("Next:\n");
260             print_tokens (t->next);
261             }
262             }
263              
264             #ifndef NOPERL
265              
266             static json_token_t *
267 4           c_tokenize (json_parse_t * parser)
268             {
269             /* The currently-parsed character. */
270            
271             char c;
272             json_token_t * r;
273              
274 4           SETUPPARSER;
275              
276             tokenize_start:
277              
278 4           switch (NEXTBYTE) {
279              
280             case '{':
281 4           r = tokenize_object (parser);
282 4           break;
283              
284             case '[':
285 0           r = tokenize_array (parser);
286 0           break;
287              
288 0           case WHITESPACE:
289 0           goto tokenize_start;
290              
291             default:
292 0           BADCHAR;
293             }
294              
295 4           check_end (parser);
296 4           return r;
297             }
298              
299             static void
300 15           tokenize_free (json_token_t * token)
301             {
302             json_token_t * next;
303 15           next = token->child;
304 15 100         if (next) {
305 5 100         if (! next->blessed) {
306 1           tokenize_free (next);
307             }
308 5           token->child = 0;
309             }
310 15           next = token->next;
311 15 100         if (next) {
312 8 100         if (! next->blessed) {
313 6           tokenize_free (next);
314             }
315 8           token->next = 0;
316             }
317 15 100         if (! token->blessed) {
318 7           Safefree (token);
319             }
320 15           }
321              
322             /* This is the entry point for validation. */
323              
324             static void
325 221           validate (SV * json, unsigned int flags)
326             {
327 221           ENTRYDECL;
328              
329 221           getstring (json, parser);
330              
331 221 100         if (parser->length == 0) {
332 1           fail_empty (parser);
333             }
334 220           c_validate (& parser_o);
335 54           }
336              
337             static void
338 0           check (json_parse_t * parser, SV * json)
339             {
340 0           getstring (json, parser);
341 0           c_validate (parser);
342 0           }
343              
344             static json_token_t *
345 4           tokenize (SV * json)
346             {
347 4           ENTRYDECL;
348              
349 4           getstring (json, parser);
350              
351             /* Mark this parser as being used for tokenizing to bypass the
352             checks for memory leaks when the parser is freed. */
353              
354 4           parser_o.tokenizing = 1;
355              
356 4           return c_tokenize (& parser_o);
357             }
358              
359             /* Make a hash containing a diagnostic error from the parser. */
360              
361 1           static SV * error_to_hash (json_parse_t * parser, char * error_as_string)
362             {
363             HV * error;
364 1           error = newHV ();
365              
366             #ifdef HK
367             #warn "Redefinition of macro HK"
368             #endif /* def HK */
369             #undef HK
370             #define HK(x, val) (void) hv_store (error, x, strlen (x), val, 0)
371              
372 1           HK("length", newSViv (parser->length));
373 1           HK("bad type", newSVpv (type_names[parser->bad_type], 0));
374 1           HK("error", newSVpv (json_errors[parser->error], 0));
375 1           HK("error as string", newSVpv (error_as_string, 0));
376 1 50         if (parser->bad_byte) {
377             int position;
378 0           position = (int) (parser->bad_byte - parser->input) + 1;
379 0           HK("bad byte position", newSViv (position));
380 0           HK("bad byte contents", newSViv (* parser->bad_byte));
381             }
382 1 50         if (parser->bad_beginning) {
383             int bcstart;
384 1           bcstart = (int) (parser->bad_beginning - parser->input) + 1;
385 1           HK("start of broken component", newSViv (bcstart));
386             }
387 1 50         if (parser->error == json_error_unexpected_character) {
388             int j;
389             AV * valid_bytes;
390 0           valid_bytes = newAV ();
391 0           make_valid_bytes (parser);
392 0 0         for (j = 0; j < JSON3MAXBYTE; j++) {
393 0           av_push (valid_bytes, newSViv (parser->valid_bytes[j]));
394             }
395 0           HK("valid bytes", newRV_inc ((SV *) valid_bytes));
396             }
397 1           return newRV_inc ((SV *) error);
398              
399             #undef HK
400             }
401              
402             #endif /* ndef NOPERL */
403