File Coverage

ByteString.xs
Criterion Covered Total %
statement 272 484 56.2
branch 143 384 37.2
condition n/a
subroutine n/a
pod n/a
total 415 868 47.8


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include "ppport.h"
6              
7             #ifndef UNLIKELY
8             # define UNLIKELY(x) (x)
9             #endif
10             #ifndef LIKELY
11             # define LIKELY(x) (x)
12             #endif
13              
14             #ifndef SvREFCNT_dec_NN
15             # define SvREFCNT_dec_NN SvREFCNT_dec
16             #endif
17              
18             #define CONCAT_PASTE(prefix, suffix) prefix ## suffix
19             #define CONCAT(prefix, suffix) CONCAT_PASTE(prefix, suffix)
20              
21             static SV** visited;
22             int visited_capacity;
23             int visited_p;
24              
25 40           static inline void reserve_visited_capacity(){
26 40 50         if( visited_p >= visited_capacity ){
27 0           visited_capacity += visited_capacity / 4;
28 0 0         Renew(visited, visited_capacity, SV*);
29             }
30 40           }
31              
32 26           static inline STRLEN estimate_str(unsigned char * str, STRLEN len){
33 26           unsigned char * str_begin = str;
34 26           STRLEN out_len = len+2;
35 208 100         for(unsigned char * str_end=str+len; str!=str_end; ++str){
36 182 50         if( *str < 0x20 ){
37 0 0         switch( *str ){
38             case '\n': case '\t': case '\r': case '\b': case '\f':
39 0           ++out_len;
40 0           break;
41             default:
42 0           out_len += 5;
43             }
44             }
45 182           else switch( *str ){
46             case '\\': case '"':
47 2           ++out_len;
48 2           break;
49             case '/':
50 3 50         if( str!=str_begin && *(str-1)=='<' )
    100          
51 1           ++out_len;
52             default:
53             ;
54             }
55             }
56 26           return out_len;
57             }
58              
59 0           static inline char hex(unsigned char ch){
60 0 0         if( ch>9 )
61 0           return 'A' + ch - 10;
62             else
63 0           return '0' + ch;
64             }
65 0           static inline unsigned int decode_hex(unsigned char ch){
66 0 0         if( ch<='9' )
67 0           return ch - '0';
68 0 0         if( ch<='Z' )
69 0           return ch - 'A' + 10;
70 0           return ch - 'a' + 10;
71             }
72              
73 26           static inline unsigned char * encode_str(unsigned char * buffer, unsigned char * str, STRLEN len){
74 26           unsigned char * str_begin = str;
75 26           *buffer++ = '"';
76 208 100         for(unsigned char * str_end=str+len; str!=str_end; ++str){
77 182 50         if( *str < 0x20 ){
78 0           *buffer++ = '\\';
79 0           switch( *str ){
80             case '\n':
81 0           *buffer++ = 'n';
82 0           break;
83             case '\t':
84 0           *buffer++ = 't';
85 0           break;
86             case '\r':
87 0           *buffer++ = 'r';
88 0           break;
89             case '\b':
90 0           *buffer++ = 'b';
91 0           break;
92             case '\f':
93 0           *buffer++ = 'f';
94 0           break;
95             default:
96 0           *buffer++ = 'u';
97 0           *buffer++ = '0';
98 0           *buffer++ = '0';
99 0           *buffer++ = hex(*str >> 4);
100 0           *buffer++ = hex(*str & 15);
101             }
102             }
103             else{
104 182           switch( *str ){
105             case '\\': case '"':
106 2           *buffer++ = '\\';
107 2           break;
108              
109             case '/':
110 3 50         if( str!=str_begin && *(str-1)=='<' )
    100          
111 1           *buffer++ = '\\';
112              
113             default:
114             ;
115             }
116 182           *buffer++ = *str;
117             }
118             }
119 26           *buffer++ = '"';
120 26           return buffer;
121             }
122              
123             #define NAME normal
124             #define UNBLESSED FALSE
125             #include "encode_gen.h"
126             #undef UNBLESSED
127             #undef NAME
128              
129             #define NAME unblessed
130             #define UNBLESSED TRUE
131             #include "encode_gen.h"
132             #undef UNBLESSED
133             #undef NAME
134              
135 10           static inline unsigned char * skip_bom(unsigned char * str, unsigned char * str_end){
136 10 100         if( str_end - str >= 3 && str[0]==(unsigned char)'\xEF' && str[1]==(unsigned char)'\xBB' && str[2]==(unsigned char)'\xBF' )
    50          
    0          
    0          
137 0           return str+3;
138 10           return str;
139             }
140              
141 61           static inline unsigned char * skip_space(unsigned char * str, unsigned char * str_end){
142 61 100         while( str!=str_end && isSPACE(*str) )
    50          
143 0           ++str;
144 61           return str;
145             }
146              
147 2           static inline bool is_identity(unsigned char ch){
148 2 50         return !isSPACE(ch) && ch!=',' && ch!=':' && ch!=']' && ch!='}';
    50          
    50          
    50          
    0          
149             }
150              
151 2           static inline bool is_key(unsigned char ch){
152 2 50         return !isSPACE(ch) && ch!=':';
    50          
153             }
154              
155 3           static inline STRLEN is_number(unsigned char * str, unsigned char * str_end){
156 3 50         if( str==str_end )
157 0           return 0;
158              
159 3           STRLEN len = 0;
160 3           bool has_digit = FALSE;
161 3 50         if( *str=='+' || *str=='-' ){
    50          
162 0           str = skip_space(str+1, str_end);
163 0           ++len;
164             }
165              
166 3 50         if( str!=str_end && isDIGIT(*str) )
    100          
167 1           has_digit = TRUE;
168 4 50         while( str!=str_end && isDIGIT(*str) ){
    100          
169 1           ++len;
170 1           ++str;
171             }
172 3 50         if( str!=str_end && *str=='.' ){
    50          
173 0           ++len;
174 0           ++str;
175             }
176 3 50         if( str!=str_end && isDIGIT(*str) )
    50          
177 0           has_digit = TRUE;
178 3 50         while( str!=str_end && isDIGIT(*str) ){
    50          
179 0           ++len;
180 0           ++str;
181             }
182 3 100         if( !has_digit )
183 2           return 0;
184              
185 1 50         if( str!=str_end && (*str=='e' || *str=='E') ){
    50          
    50          
186 0           ++len;
187 0           ++str;
188 0 0         if( str!=str_end && (*str=='+' || *str=='-') ){
    0          
    0          
189 0           ++len;
190 0           ++str;
191             }
192 0 0         while( str!=str_end && isDIGIT(*str) ){
    0          
193 0           ++len;
194 0           ++str;
195             }
196             }
197 1           return len;
198             }
199              
200 3           static inline unsigned char * decode_number_r(unsigned char * str, unsigned char * str_end, unsigned char ** out, unsigned char ** out_capacity_end, unsigned char ** out_end){
201 3           STRLEN len = is_number(str, str_end);
202 3 100         if( len<=0 ){
203 2           *out_end = NULL;
204 2           return str;
205             }
206              
207 1 50         if( !*out ){
208 1           Newx(*out, len+1, unsigned char);
209 1           *out_capacity_end = *out + len + 1;
210             }
211 0 0         else if( *out_capacity_end - *out < len + 1 ){
212 0           Renew(*out, len+1, unsigned char);
213 0           *out_capacity_end = *out + len + 1;
214             }
215              
216 1           *out_end = *out + len;
217 1           **out_end = 0;
218 1           unsigned char * out_cur = *out;
219              
220 1 50         if( *str=='+' || *str=='-' ){
    50          
221 0           *out_cur++ = *str;
222 0           --len;
223 0           str = skip_space(str+1, str_end);
224             }
225 2 100         while( len-- )
226 1           *out_cur++ = *str++;
227 1           return str;
228             }
229              
230 4           static inline STRLEN estimate_orig_key(unsigned char * str, unsigned char * str_end){
231 4 50         if( str==str_end )
232 0           return 0;
233 4 100         if( *str=='"' || *str=='\'' ){
    50          
234 3           char delimiter = *str;
235 3           ++str;
236 3           STRLEN len = 0;
237             while(TRUE){
238 28 50         if( str==str_end )
239 0           return -1;
240 28 100         if( *str==delimiter )
241 3           return len;
242 25 50         if( *str=='\\' ){
243 0           ++str;
244 0           switch( *str++ ){
245             case 'u': {
246 0           unsigned int d = 0;
247              
248 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
249 0           d = (d << 4) + decode_hex(*str++);
250 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
251 0           d = (d << 4) + decode_hex(*str++);
252 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
253 0           d = (d << 4) + decode_hex(*str++);
254 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
255 0           d = (d << 4) + decode_hex(*str++);
256              
257 0 0         if( d <= 0x7f )
258 0           ++len;
259 0 0         else if( d <= 0x7ff )
260 0           len += 2;
261 0 0         else if( d <= 0xffff )
262 0           len += 3;
263             else
264 0           len += 4;
265              
266 0           break;
267             }
268             case 'n': case '\\': case 't': case 'r': case '/': case 'b': case 'f':
269 0           ++len;
270 0           break;
271             default:
272 0 0         if( *(str-1)==delimiter )
273 0           ++len;
274             else
275 0           len += 2;
276             }
277             }
278             else{
279 25           ++len;
280 25           ++str;
281             }
282 25           }
283             }
284             else{
285 1           STRLEN len = 0;
286 2 100         while( str!=str_end && is_key(*str) ){
    50          
287 1           ++len;
288 1           ++str;
289             }
290 1           return len;
291             }
292             }
293              
294 7           static inline STRLEN estimate_orig_str(unsigned char * str, unsigned char * str_end){
295 7 50         if( str==str_end )
296 0           return -1;
297 7 50         if( *str=='"' || *str=='\'' ){
    0          
298 7           char delimiter = *str;
299 7           ++str;
300 7           STRLEN len = 0;
301             while(TRUE){
302 89 100         if( str==str_end )
303 1           return -1;
304 88 100         if( *str==delimiter )
305 6           return len;
306 82 100         if( *str=='\\' ){
307 4           ++str;
308 4           switch( *str++ ){
309             case 'u': {
310 0           unsigned int d = 0;
311              
312 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
313 0           d = (d << 4) + decode_hex(*str++);
314 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
315 0           d = (d << 4) + decode_hex(*str++);
316 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
317 0           d = (d << 4) + decode_hex(*str++);
318 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
319 0           d = (d << 4) + decode_hex(*str++);
320              
321 0 0         if( d <= 0x7f )
322 0           ++len;
323 0 0         else if( d <= 0x7ff )
324 0           len += 2;
325 0 0         else if( d <= 0xffff )
326 0           len += 3;
327             else
328 0           len += 4;
329              
330 0           break;
331             }
332             case 'n': case '\\': case 't': case 'r': case '/': case 'b': case 'f':
333 2           ++len;
334 2           break;
335             default:
336 2 100         if( *(str-1)==delimiter )
337 1           ++len;
338             else
339 4           len += 2;
340             }
341             }
342             else{
343 78           ++len;
344 78           ++str;
345             }
346 82           }
347             }
348             else
349 0           return -1;
350             }
351              
352 4           static inline unsigned char * decode_key_r(unsigned char * str, unsigned char * str_end, unsigned char ** out, unsigned char ** out_capacity_end, unsigned char ** out_end){
353 4           STRLEN len = estimate_orig_key(str, str_end);
354 4 50         if( len==-1 ){
355 0           *out_end = NULL;
356 0           return str;
357             }
358              
359 4 50         if( !*out ){
360 4           Newx(*out, len+1, unsigned char);
361 4           *out_capacity_end = *out + len + 1;
362             }
363 0 0         else if( *out_capacity_end - *out < len + 1 ){
364 0           Renew(*out, len+1, unsigned char);
365 0           *out_capacity_end = *out + len + 1;
366             }
367              
368 4           *out_end = *out + len;
369 4           **out_end = 0;
370 4           unsigned char * out_cur = *out;
371              
372 4 100         if( *str=='"' || *str=='\'' ){
    50          
373 3           char delimiter = *str;
374 3           ++str;
375             while(TRUE){
376 28 100         if( *str==delimiter )
377 3           return str+1;
378 25 50         if( *str=='\\' ){
379 0           ++str;
380 0           switch( *str++ ){
381             case 'u': {
382 0           unsigned int d = 0;
383              
384 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
385 0           d = (d << 4) + decode_hex(*str++);
386 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
387 0           d = (d << 4) + decode_hex(*str++);
388 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
389 0           d = (d << 4) + decode_hex(*str++);
390 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
391 0           d = (d << 4) + decode_hex(*str++);
392              
393 0 0         if( d <= 0x7f )
394 0           *out_cur++ = (unsigned char) d;
395 0 0         else if( d <= 0x7ff ){
396 0           *out_cur++ = (unsigned char)( d >> 6 | 0xC0);
397 0           *out_cur++ = (unsigned char)((d & 0x3F) | 0x80);
398             }
399 0 0         else if( d <= 0xffff ){
400 0           *out_cur++ = (unsigned char)( d >> 12 | 0xE0);
401 0           *out_cur++ = (unsigned char)((d >> 6 & 0x3F) | 0x80);
402 0           *out_cur++ = (unsigned char)((d & 0x3F) | 0x80);
403             }
404             else{
405 0           *out_cur++ = (unsigned char)( d >> 18 | 0xF0);
406 0           *out_cur++ = (unsigned char)((d >> 12 & 0x3F) | 0x80);
407 0           *out_cur++ = (unsigned char)((d >> 6 & 0x3F) | 0x80);
408 0           *out_cur++ = (unsigned char)((d & 0x3F) | 0x80);
409             }
410              
411 0           break;
412             }
413             case 'n':
414 0           *out_cur++ = '\n';
415 0           break;
416             case '\\':
417 0           *out_cur++ = '\\';
418 0           break;
419             case 't':
420 0           *out_cur++ = '\t';
421 0           break;
422             case 'r':
423 0           *out_cur++ = '\r';
424 0           break;
425             case '/':
426 0           *out_cur++ = '/';
427 0           break;
428             case 'b':
429 0           *out_cur++ = '\b';
430 0           break;
431             case 'f':
432 0           *out_cur++ = '\f';
433 0           break;
434             default:
435 0 0         if( *(str-1)!=delimiter )
436 0           *out_cur++ = '\\';
437 0           *out_cur++ = *(str-1);
438             }
439             }
440             else
441 25           *out_cur++ = *str++;
442 25           }
443             }
444             else{
445 2 100         while( str!=str_end && is_key(*str) )
    50          
446 1           *out_cur++ = *str++;
447 1           return str;
448             }
449             }
450              
451 7           static inline unsigned char * decode_str_r(unsigned char * str, unsigned char * str_end, unsigned char ** out, unsigned char ** out_capacity_end, unsigned char ** out_end){
452 7           STRLEN len = estimate_orig_str(str, str_end);
453 7 100         if( len==-1 ){
454 1           *out_end = NULL;
455 1           return str;
456             }
457              
458 6 50         if( !*out ){
459 6           Newx(*out, len+1, unsigned char);
460 6           *out_capacity_end = *out + len + 1;
461             }
462 0 0         else if( *out_capacity_end - *out < len + 1 ){
463 0           Renew(*out, len+1, unsigned char);
464 0           *out_capacity_end = *out + len + 1;
465             }
466              
467 6           *out_end = *out + len;
468 6           **out_end = 0;
469 6           unsigned char * out_cur = *out;
470              
471 6           char delimiter = *str;
472 6           ++str;
473             while(TRUE){
474 81 100         if( *str==delimiter )
475 6           return str+1;
476 75 100         if( *str=='\\' ){
477 4           ++str;
478 4           switch( *str++ ){
479             case 'u': {
480 0           unsigned int d = 0;
481              
482 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
483 0           d = (d << 4) + decode_hex(*str++);
484 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
485 0           d = (d << 4) + decode_hex(*str++);
486 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
487 0           d = (d << 4) + decode_hex(*str++);
488 0 0         if( str!=str_end && isXDIGIT(*str) )
    0          
489 0           d = (d << 4) + decode_hex(*str++);
490              
491 0 0         if( d <= 0x7f )
492 0           *out_cur++ = (unsigned char) d;
493 0 0         else if( d <= 0x7ff ){
494 0           *out_cur++ = (unsigned char)( d >> 6 | 0xC0);
495 0           *out_cur++ = (unsigned char)((d & 0x3F) | 0x80);
496             }
497 0 0         else if( d <= 0xffff ){
498 0           *out_cur++ = (unsigned char)( d >> 12 | 0xE0);
499 0           *out_cur++ = (unsigned char)((d >> 6 & 0x3F) | 0x80);
500 0           *out_cur++ = (unsigned char)((d & 0x3F) | 0x80);
501             }
502             else{
503 0           *out_cur++ = (unsigned char)( d >> 18 | 0xF0);
504 0           *out_cur++ = (unsigned char)((d >> 12 & 0x3F) | 0x80);
505 0           *out_cur++ = (unsigned char)((d >> 6 & 0x3F) | 0x80);
506 0           *out_cur++ = (unsigned char)((d & 0x3F) | 0x80);
507             }
508              
509 0           break;
510             }
511             case 'n':
512 0           *out_cur++ = '\n';
513 0           break;
514             case '\\':
515 0           *out_cur++ = '\\';
516 0           break;
517             case 't':
518 0           *out_cur++ = '\t';
519 0           break;
520             case 'r':
521 0           *out_cur++ = '\r';
522 0           break;
523             case '/':
524 2           *out_cur++ = '/';
525 2           break;
526             case 'b':
527 0           *out_cur++ = '\b';
528 0           break;
529             case 'f':
530 0           *out_cur++ = '\f';
531 0           break;
532             default:
533 2 100         if( *(str-1)!=delimiter )
534 1           *out_cur++ = '\\';
535 4           *out_cur++ = *(str-1);
536             }
537             }
538             else
539 71           *out_cur++ = *str++;
540 75           }
541             }
542              
543             // the created SV has refcnt=1
544 23           unsigned char * decode(unsigned char * str, unsigned char * str_end, SV**out){
545 23           str = skip_space(str, str_end);
546 23 50         if( str==str_end )
547 0           goto GIVEUP;
548              
549 23           switch( *str ){
550             case '[': {
551 7           AV * av = newAV();
552 7           *out = newRV_noinc((SV*) av);
553 7           str = skip_space(str+1, str_end);
554              
555             while(TRUE){
556 10 50         if( str==str_end )
557 3           goto ROLLBACK;
558 10 50         if( *str == ']' )
559 4           return str+1;
560              
561             SV * elem;
562 10           str = decode(str, str_end, &elem);
563 10 100         if( elem==NULL )
564 3           goto ROLLBACK;
565 7           av_push(av, elem);
566              
567 7           str = skip_space(str, str_end);
568 7 50         if( str==str_end )
569 0           goto ROLLBACK;
570 7 100         if( *str == ']' )
571 4           return str+1;
572 3 50         if( *str==',' )
573 3           str = skip_space(str+1, str_end);
574             else
575 0           goto ROLLBACK;
576 3           }
577             }
578             case '{': {
579 4           HV * hv = newHV();
580 4           *out = newRV_noinc((SV*) hv);
581 4           str = skip_space(str+1, str_end);
582 4           unsigned char *key_buffer=0, *key_buffer_end, *key_end;
583             while(TRUE){
584 4 50         if( str==str_end ){
585 0 0         if( key_buffer )
586 0           Safefree(key_buffer);
587 1           goto ROLLBACK;
588             }
589 4 50         if( *str=='}' ){
590 0 0         if( key_buffer )
591 0           Safefree(key_buffer);
592 3           return str+1;
593             }
594 4           str = decode_key_r(str, str_end, &key_buffer, &key_buffer_end, &key_end);
595 4 50         if( !key_end ){
596 0 0         if( key_buffer )
597 0           Safefree(key_buffer);
598 0           goto ROLLBACK;
599             }
600 4           str = skip_space(str, str_end);
601              
602 4           SV * elem = NULL;
603 4 100         if( *str==':' )
604 3           str = decode(str+1, str_end, &elem);
605 4 100         if( elem==NULL ){
606 1           Safefree(key_buffer);
607 1           goto ROLLBACK;
608             }
609 3           hv_store(hv, (char*)key_buffer, key_end-key_buffer, elem, 0);
610              
611 3           str = skip_space(str, str_end);
612 3 50         if( str==str_end ){
613 0           Safefree(key_buffer);
614 0           goto ROLLBACK;
615             }
616 3 50         if( *str=='}' ){
617 3           Safefree(key_buffer);
618 3           return str+1;
619             }
620 0 0         if( *str==',' )
621 0           str = skip_space(str+1, str_end);
622             else{
623 0           Safefree(key_buffer);
624 0           goto ROLLBACK;
625             }
626 0           }
627             break;
628             }
629             case '"': case '\'': {
630 7           unsigned char *value_buffer=0, *value_buffer_end, *value_end;
631 7           str = decode_str_r(str, str_end, &value_buffer, &value_buffer_end, &value_end);
632 7 100         if( !value_end )
633 1           goto GIVEUP;
634 6           *out = newSV(0);
635 6           sv_upgrade(*out, SVt_PV);
636 6           SvPOK_on(*out);
637 6           SvPV_set(*out, (char*)value_buffer);
638 6           SvCUR_set(*out, value_end - value_buffer);
639 6           SvLEN_set(*out, value_buffer_end - value_buffer);
640 6           return str;
641             }
642             default: {
643 5 50         if( str_end-str==4 || (str_end-str>4 && !is_identity(str[4])) ){
    100          
    50          
644 2 50         if( (str[0]=='T' || str[0]=='t') && (str[1]=='R' || str[1]=='r') && (str[2]=='U' || str[2]=='u') && (str[3]=='E' || str[3]=='e') ){
    50          
    0          
    0          
    0          
    0          
    0          
    0          
645 0           *out = newSViv(1);
646 3           return str+4;
647             }
648 2 50         if( (str[0]=='N' || str[0]=='n') && (str[1]=='U' || str[1]=='u') && (str[2]=='L' || str[2]=='l') && (str[3]=='L' || str[3]=='l') ){
    50          
    50          
    50          
    50          
    50          
    50          
    50          
649 2           *out = newSV(0);
650 2           return str+4;
651             }
652             }
653 3 50         if( str_end-str==5 || (str_end-str>5 && !is_identity(str[5])) ){
    50          
    0          
654 0 0         if( (str[0]=='F' || str[0]=='f') && (str[1]=='A' || str[1]=='a') && (str[2]=='L' || str[2]=='l') && (str[3]=='S' || str[3]=='s') && (str[4]=='E' || str[4]=='e') ){
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
655 0           *out = newSVpvn("", 0);
656 0           return str+5;
657             }
658             }
659              
660 3           unsigned char *value_buffer=0, *value_buffer_end, *value_end;
661 3           str = decode_number_r(str, str_end, &value_buffer, &value_buffer_end, &value_end);
662 3 100         if( value_end ){
663 1           *out = newSV(0);
664 1           sv_upgrade(*out, SVt_PV);
665 1           SvPOK_on(*out);
666 1           SvPV_set(*out, (char*)value_buffer);
667 1           SvCUR_set(*out, value_end - value_buffer);
668 1           SvLEN_set(*out, value_buffer_end - value_buffer);
669 1           return str;
670             }
671              
672 2           goto GIVEUP;
673             }
674             }
675              
676             ROLLBACK:
677 4           SvREFCNT_dec_NN(*out);
678             GIVEUP:
679 7           *out = NULL;
680 7           return str;
681             }
682              
683             MODULE = JSON::XS::ByteString PACKAGE = JSON::XS::ByteString
684              
685             void
686             encode_json(SV * data)
687             PPCODE:
688 15           visited_p = 0;
689 15           STRLEN need_size = estimate_normal(data);
690 15           SV * out_sv = sv_2mortal(newSV(need_size));
691 15           SvPOK_only(out_sv);
692 15           visited_p = 0;
693 15           char * cur = (char*)encode_normal((unsigned char*)SvPVX(out_sv), data);
694 15           SvCUR_set(out_sv, cur - SvPVX(out_sv));
695 15           *SvEND(out_sv) = 0;
696 15           PUSHs(out_sv);
697              
698             void
699             encode_json_unblessed(SV * data)
700             PPCODE:
701 1           visited_p = 0;
702 1           STRLEN need_size = estimate_unblessed(data);
703 1           SV * out_sv = sv_2mortal(newSV(need_size));
704 1           SvPOK_only(out_sv);
705 1           visited_p = 0;
706 1           char * cur = (char*)encode_unblessed((unsigned char*)SvPVX(out_sv), data);
707 1           SvCUR_set(out_sv, cur - SvPVX(out_sv));
708 1           *SvEND(out_sv) = 0;
709 1           PUSHs(out_sv);
710              
711             void
712             decode_json(SV * json, bool warn2die=FALSE)
713             PPCODE:
714             unsigned char *str, *str_end, *str_adv;
715             STRLEN len;
716 9           SV * out = NULL;
717 9 50         str = (unsigned char*) SvPV(json, len);
718 9           str_end = str + len;
719 9           str_adv = skip_space(decode(skip_bom(str, str_end), str_end, &out), str_end);
720 9 100         if( str_end != str_adv ){
721 3 100         if( warn2die )
722 1           croak("decode_json: Unconsumed characters from offset %d", (int)(str_adv-str));
723             else{
724 2           warn("decode_json: Unconsumed characters from offset %d", (int)(str_adv-str));
725 2           SvREFCNT_dec(out);
726 2           PUSHs(&PL_sv_undef);
727             }
728             }
729 6 100         else if( out==NULL ){
730 1 50         if( warn2die )
731 0           croak("decode_json: Unconsumed characters from offset %d", (int)(str_adv-str));
732             else{
733 1           warn("decode_json: Unconsumed characters from offset %d", (int)(str_adv-str));
734 1           PUSHs(&PL_sv_undef);
735             }
736             }
737             else
738 5           PUSHs(sv_2mortal(out));
739              
740             void
741             decode_json_safe(SV * json)
742             PPCODE:
743             unsigned char *str, *str_end, *str_adv;
744             STRLEN len;
745 1           SV * out = NULL;
746 1 50         str = (unsigned char*) SvPV(json, len);
747 1           str_end = str + len;
748 1           str_adv = skip_space(decode(skip_bom(str, str_end), str_end, &out), str_end);
749 1 50         if( str_end != str_adv ){
750 0           SvREFCNT_dec(out);
751 0           PUSHs(&PL_sv_undef);
752             }
753 1 50         else if( out==NULL )
754 0           PUSHs(&PL_sv_undef);
755             else
756 1           PUSHs(sv_2mortal(out));
757              
758             BOOT:
759 1           visited_capacity = 32;
760 1 50         Newx(visited, visited_capacity, SV*);