File Coverage

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