File Coverage

json-entry-points.c
Criterion Covered Total %
statement 134 158 84.8
branch 24 34 70.5
condition n/a
subroutine n/a
pod n/a
total 158 192 82.2


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