File Coverage

blib/lib/JSON/PP.pm
Criterion Covered Total %
statement 835 951 87.8
branch 467 622 75.0
condition 181 263 68.8
subroutine 131 166 78.9
pod 46 96 47.9
total 1660 2098 79.1


line stmt bran cond sub pod time code
1             package JSON::PP;
2              
3             # JSON-2.0
4              
5 64     64   4228381 use 5.008;
  64         733  
6 64     64   411 use strict;
  64         130  
  64         1523  
7              
8 64     64   339 use Exporter ();
  64         144  
  64         2415  
9 64     64   2559 BEGIN { our @ISA = ('Exporter') }
10              
11 64     64   61898 use overload ();
  64         51892  
  64         1700  
12 64     64   26786 use JSON::PP::Boolean;
  64         188  
  64         1715  
13              
14 64     64   435 use Carp ();
  64         154  
  64         1270  
15 64     64   375 use Scalar::Util qw(blessed reftype refaddr);
  64         133  
  64         6495  
16             #use Devel::Peek;
17              
18             our $VERSION = '4.16';
19              
20             our @EXPORT = qw(encode_json decode_json from_json to_json);
21              
22             # instead of hash-access, i tried index-access for speed.
23             # but this method is not faster than what i expected. so it will be changed.
24              
25 64     64   531 use constant P_ASCII => 0;
  64         162  
  64         7981  
26 64     64   416 use constant P_LATIN1 => 1;
  64         149  
  64         4156  
27 64     64   405 use constant P_UTF8 => 2;
  64         144  
  64         3426  
28 64     64   395 use constant P_INDENT => 3;
  64         168  
  64         3355  
29 64     64   544 use constant P_CANONICAL => 4;
  64         193  
  64         3099  
30 64     64   360 use constant P_SPACE_BEFORE => 5;
  64         109  
  64         3297  
31 64     64   392 use constant P_SPACE_AFTER => 6;
  64         135  
  64         3098  
32 64     64   404 use constant P_ALLOW_NONREF => 7;
  64         189  
  64         3492  
33 64     64   394 use constant P_SHRINK => 8;
  64         156  
  64         3333  
34 64     64   383 use constant P_ALLOW_BLESSED => 9;
  64         147  
  64         3757  
35 64     64   1330 use constant P_CONVERT_BLESSED => 10;
  64         164  
  64         3638  
36 64     64   390 use constant P_RELAXED => 11;
  64         130  
  64         2850  
37              
38 64     64   477 use constant P_LOOSE => 12;
  64         139  
  64         3040  
39 64     64   384 use constant P_ALLOW_BIGNUM => 13;
  64         131  
  64         3163  
40 64     64   366 use constant P_ALLOW_BAREKEY => 14;
  64         178  
  64         3168  
41 64     64   546 use constant P_ALLOW_SINGLEQUOTE => 15;
  64         165  
  64         3353  
42 64     64   438 use constant P_ESCAPE_SLASH => 16;
  64         192  
  64         3255  
43 64     64   401 use constant P_AS_NONBLESSED => 17;
  64         117  
  64         3128  
44              
45 64     64   392 use constant P_ALLOW_UNKNOWN => 18;
  64         144  
  64         3359  
46 64     64   448 use constant P_ALLOW_TAGS => 19;
  64         126  
  64         4524  
47              
48 64   50 64   527 use constant USE_B => $ENV{PERL_JSON_PP_USE_B} || 0;
  64         173  
  64         4519  
49 64     64   471 use constant CORE_BOOL => defined &builtin::is_bool;
  64         136  
  64         8776  
50              
51             my $invalid_char_re;
52              
53             BEGIN {
54 64     64   294 $invalid_char_re = "[";
55 64         205 for my $i (0 .. 0x01F, 0x22, 0x5c) { # '/' is ok
56 2176         3398 $invalid_char_re .= quotemeta chr utf8::unicode_to_native($i);
57             }
58              
59 64         3624 $invalid_char_re = qr/$invalid_char_re]/;
60             }
61              
62             BEGIN {
63 64     64   7785 if (USE_B) {
64             require B;
65             }
66             }
67              
68             BEGIN {
69 64     64   473 my @xs_compati_bit_properties = qw(
70             latin1 ascii utf8 indent canonical space_before space_after allow_nonref shrink
71             allow_blessed convert_blessed relaxed allow_unknown
72             allow_tags
73             );
74 64         196 my @pp_bit_properties = qw(
75             allow_singlequote allow_bignum loose
76             allow_barekey escape_slash as_nonblessed
77             );
78              
79 64         193 for my $name (@xs_compati_bit_properties, @pp_bit_properties) {
80 1280         5007 my $property_id = 'P_' . uc($name);
81              
82 1280 50   2 1 200715 eval qq/
  2 50   1 1 605  
  2 50   2 1 7  
  2 50   24653 1 8  
  0 50   1 1 0  
  2 50   1 1 6  
  1 100   3 1 6  
  1 100   0 0 3  
  1 50   12292 1 5  
  0 50   10 1 0  
  1 50   4 1 3  
  2 50   1 1 338  
  2 100   0 0 11  
  2 100   0 0 7  
  0 0   0 0 0  
  2 0   0 0 5  
  24653 100   0 0 101559  
  24653 50   0 0 52768  
  9286 100   0 0 22924  
  15367 50   0 0 33075  
  24653 50   0 0 412307  
  1 50   0 0 951  
  1 50   0 0 4  
  1 50   0 0 3  
  0 0   0 0 0  
  1 0   0 0 3  
  1 0   0 0 5  
  1 0   0 0 2  
  1 0   0 0 4  
  0 0   0 0 0  
  1 0   0 0 31  
  3 0   309 0 849  
  3 0   6 1 12  
  2 0   2 1 7  
  1 0   0 1 3  
  3 0   14 1 7  
  0 0   21504 1 0  
  0 0   7 1 0  
  0 0   6 1 0  
  0 0   18466 1 0  
  0 0       0  
  12292 0       40467  
  12292 0       29253  
  12292 100       25050  
  0 50       0  
  12292 100       90634  
  10 50       183  
  10 50       33  
  10 0       33  
  0 0       0  
  10 50       27  
  4 50       23  
  4 50       13  
  4 50       22  
  0 50       0  
  4 100       42  
  1 50       7  
  1 100       3  
  1 100       3  
  0 50       0  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  309         1457  
  6         557  
  6         17  
  4         6  
  2         5  
  6         99  
  2         11  
  2         7  
  2         16  
  0         0  
  2         38  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  14         48  
  14         31  
  14         46  
  0         0  
  14         43  
  21504         71795  
  21504         43540  
  21504         52691  
  0         0  
  21504         89912  
  7         22  
  7         17  
  4         9  
  3         5  
  7         13  
  6         19  
  6         18  
  4         9  
  2         5  
  6         80  
  18466         59798  
  18466         36974  
  18466         36318  
  0         0  
  18466         281900  
83             sub $name {
84             my \$enable = defined \$_[1] ? \$_[1] : 1;
85              
86             if (\$enable) {
87             \$_[0]->{PROPS}->[$property_id] = 1;
88             }
89             else {
90             \$_[0]->{PROPS}->[$property_id] = 0;
91             }
92              
93             \$_[0];
94             }
95              
96             sub get_$name {
97             \$_[0]->{PROPS}->[$property_id] ? 1 : '';
98             }
99             /;
100             }
101              
102             }
103              
104              
105              
106             # Functions
107              
108             my $JSON; # cache
109              
110             sub encode_json ($) { # encode
111 186   66 186 1 1082 ($JSON ||= __PACKAGE__->new->utf8)->encode(@_);
112             }
113              
114              
115             sub decode_json { # decode
116 6206   66 6206 1 79170 ($JSON ||= __PACKAGE__->new->utf8)->decode(@_);
117             }
118              
119             # Obsoleted
120              
121             sub to_json($) {
122 0     0 0 0 Carp::croak ("JSON::PP::to_json has been renamed to encode_json.");
123             }
124              
125              
126             sub from_json($) {
127 0     0 0 0 Carp::croak ("JSON::PP::from_json has been renamed to decode_json.");
128             }
129              
130              
131             # Methods
132              
133             sub new {
134 43174     43174 1 2090439 my $class = shift;
135 43174         134536 my $self = {
136             max_depth => 512,
137             max_size => 0,
138             indent_length => 3,
139             };
140              
141 43174         109488 $self->{PROPS}[P_ALLOW_NONREF] = 1;
142              
143 43174         1073978 bless $self, $class;
144             }
145              
146              
147             sub encode {
148 25141     25141 1 142623 return $_[0]->PP_encode_json($_[1]);
149             }
150              
151              
152             sub decode {
153 24952     24952 1 125779 return $_[0]->PP_decode_json($_[1], 0x00000000);
154             }
155              
156              
157             sub decode_prefix {
158 8     8 1 925 return $_[0]->PP_decode_json($_[1], 0x00000001);
159             }
160              
161              
162             # accessor
163              
164              
165             # pretty printing
166              
167             sub pretty {
168 5     5 1 2465 my ($self, $v) = @_;
169 5 50       16 my $enable = defined $v ? $v : 1;
170              
171 5 100       13 if ($enable) { # indent_length(3) for JSON::XS compatibility
172 3         65 $self->indent(1)->space_before(1)->space_after(1);
173             }
174             else {
175 2         48 $self->indent(0)->space_before(0)->space_after(0);
176             }
177              
178 5         13 $self;
179             }
180              
181             # etc
182              
183             sub max_depth {
184 5 50   5 1 1259 my $max = defined $_[1] ? $_[1] : 0x80000000;
185 5         12 $_[0]->{max_depth} = $max;
186 5         38 $_[0];
187             }
188              
189              
190 383     383 0 840 sub get_max_depth { $_[0]->{max_depth}; }
191              
192              
193             sub max_size {
194 3 50   3 1 358 my $max = defined $_[1] ? $_[1] : 0;
195 3         8 $_[0]->{max_size} = $max;
196 3         13 $_[0];
197             }
198              
199              
200 383     383 0 721 sub get_max_size { $_[0]->{max_size}; }
201              
202             sub boolean_values {
203 6     6 1 2155 my $self = shift;
204 6 100       18 if (@_) {
205 4         10 my ($false, $true) = @_;
206 4         13 $self->{false} = $false;
207 4         7 $self->{true} = $true;
208 4         7 if (CORE_BOOL) {
209 64     64   125631 BEGIN { CORE_BOOL and warnings->unimport(qw(experimental::builtin)) }
210             if (builtin::is_bool($true) && builtin::is_bool($false) && $true && !$false) {
211             $self->{core_bools} = !!1;
212             }
213             else {
214             delete $self->{core_bools};
215             }
216             }
217             } else {
218 2         5 delete $self->{false};
219 2         3 delete $self->{true};
220 2         4 delete $self->{core_bools};
221             }
222 6         13 return $self;
223             }
224              
225             sub core_bools {
226 1     1 1 3 my $self = shift;
227 1 50       5 my $core_bools = defined $_[0] ? $_[0] : 1;
228 1 50       4 if ($core_bools) {
229 1         2 $self->{true} = !!1;
230 1         2 $self->{false} = !!0;
231 1         4 $self->{core_bools} = !!1;
232             }
233             else {
234 0         0 $self->{true} = $JSON::PP::true;
235 0         0 $self->{false} = $JSON::PP::false;
236 0         0 $self->{core_bools} = !!0;
237             }
238 1         2 return $self;
239             }
240              
241             sub get_core_bools {
242 3     3 0 14 my $self = shift;
243 3         16 return !!$self->{core_bools};
244             }
245              
246             sub unblessed_bool {
247 0     0 0 0 my $self = shift;
248 0         0 return $self->core_bools(@_);
249             }
250              
251             sub get_unblessed_bool {
252 0     0 0 0 my $self = shift;
253 0         0 return $self->get_core_bools(@_);
254             }
255              
256             sub get_boolean_values {
257 5     5 0 3334 my $self = shift;
258 5 50 66     28 if (exists $self->{true} and exists $self->{false}) {
259 3         15 return @$self{qw/false true/};
260             }
261 2         8 return;
262             }
263              
264             sub filter_json_object {
265 3 100 66 3 1 19 if (defined $_[1] and ref $_[1] eq 'CODE') {
266 2         5 $_[0]->{cb_object} = $_[1];
267             } else {
268 1         3 delete $_[0]->{cb_object};
269             }
270 3 50 66     13 $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
271 3         16 $_[0];
272             }
273              
274             sub filter_json_single_key_object {
275 4 50 33 4 1 22 if (@_ == 1 or @_ > 3) {
276 0         0 Carp::croak("Usage: JSON::PP::filter_json_single_key_object(self, key, callback = undef)");
277             }
278 4 100 66     18 if (defined $_[2] and ref $_[2] eq 'CODE') {
279 3         10 $_[0]->{cb_sk_object}->{$_[1]} = $_[2];
280             } else {
281 1         8 delete $_[0]->{cb_sk_object}->{$_[1]};
282 1 50       2 delete $_[0]->{cb_sk_object} unless %{$_[0]->{cb_sk_object} || {}};
  1 50       5  
283             }
284 4 50 33     13 $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
285 4         8 $_[0];
286             }
287              
288             sub indent_length {
289 0 0 0 0 1 0 if (!defined $_[1] or $_[1] > 15 or $_[1] < 0) {
      0        
290 0         0 Carp::carp "The acceptable range of indent_length() is 0 to 15.";
291             }
292             else {
293 0         0 $_[0]->{indent_length} = $_[1];
294             }
295 0         0 $_[0];
296             }
297              
298             sub get_indent_length {
299 0     0 0 0 $_[0]->{indent_length};
300             }
301              
302             sub sort_by {
303 3 50   3 1 1499 $_[0]->{sort_by} = defined $_[1] ? $_[1] : 1;
304 3         11 $_[0];
305             }
306              
307             sub allow_bigint {
308 0     0 0 0 Carp::carp("allow_bigint() is obsoleted. use allow_bignum() instead.");
309 0         0 $_[0]->allow_bignum;
310             }
311              
312             ###############################
313              
314             ###
315             ### Perl => JSON
316             ###
317              
318              
319             { # Convert
320              
321             my $max_depth;
322             my $indent;
323             my $ascii;
324             my $latin1;
325             my $utf8;
326             my $space_before;
327             my $space_after;
328             my $canonical;
329             my $allow_blessed;
330             my $convert_blessed;
331              
332             my $indent_length;
333             my $escape_slash;
334             my $bignum;
335             my $as_nonblessed;
336             my $allow_tags;
337              
338             my $depth;
339             my $indent_count;
340             my $keysort;
341              
342              
343             sub PP_encode_json {
344 25141     25141 0 39052 my $self = shift;
345 25141         37602 my $obj = shift;
346              
347 25141         35025 $indent_count = 0;
348 25141         35634 $depth = 0;
349              
350 25141         41225 my $props = $self->{PROPS};
351              
352             ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed,
353             $convert_blessed, $escape_slash, $bignum, $as_nonblessed, $allow_tags)
354 25141         44524 = @{$props}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED,
  25141         88860  
355             P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED, P_ALLOW_TAGS];
356              
357 25141         39744 ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/};
  25141         50824  
358              
359 25141 100   586   56873 $keysort = $canonical ? sub { $a cmp $b } : undef;
  586         1223  
360              
361 25141 100       64094 if ($self->{sort_by}) {
362             $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by}
363             : $self->{sort_by} =~ /\D+/ ? $self->{sort_by}
364 3 100   19   31 : sub { $a cmp $b };
  19 100       37  
365             }
366              
367 25141 50 66     66642 encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)")
368             if(!ref $obj and !$props->[ P_ALLOW_NONREF ]);
369              
370 25141         60496 my $str = $self->object_to_json($obj);
371              
372 25123 100       58107 $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible
373              
374 25123         81225 return $str;
375             }
376              
377              
378             sub object_to_json {
379 25491     25491 0 47934 my ($self, $obj) = @_;
380 25491         43954 my $type = ref($obj);
381              
382 25491 100       71869 if($type eq 'HASH'){
    100          
    100          
383 346         1071 return $self->hash_to_json($obj);
384             }
385             elsif($type eq 'ARRAY'){
386 25010         61768 return $self->array_to_json($obj);
387             }
388             elsif ($type) { # blessed object?
389 54 100       196 if (blessed($obj)) {
390              
391 34 100       188 return $self->value_to_json($obj) if ( $obj->isa('JSON::PP::Boolean') );
392              
393 14 100 100     75 if ( $allow_tags and $obj->can('FREEZE') ) {
394 1   33     5 my $obj_class = ref $obj || $obj;
395 1         3 $obj = bless $obj, $obj_class;
396 1         5 my @results = $obj->FREEZE('JSON');
397 1 50 33     1076 if ( @results and ref $results[0] ) {
398 0 0       0 if ( refaddr( $obj ) eq refaddr( $results[0] ) ) {
399 0         0 encode_error( sprintf(
400             "%s::FREEZE method returned same object as was passed instead of a new one",
401             ref $obj
402             ) );
403             }
404             }
405 1         10 return '("'.$obj_class.'")['.join(',', @results).']';
406             }
407              
408 13 100 100     92 if ( $convert_blessed and $obj->can('TO_JSON') ) {
409 5         16 my $result = $obj->TO_JSON();
410 5 100 66     881 if ( defined $result and ref( $result ) ) {
411 2 100       13 if ( refaddr( $obj ) eq refaddr( $result ) ) {
412 1         7 encode_error( sprintf(
413             "%s::TO_JSON method returned same object as was passed instead of a new one",
414             ref $obj
415             ) );
416             }
417             }
418              
419 4         23 return $self->object_to_json( $result );
420             }
421              
422 8 100 66     25 return "$obj" if ( $bignum and _is_bignum($obj) );
423              
424 5 100       10 if ($allow_blessed) {
425 3 50       6 return $self->blessed_to_json($obj) if ($as_nonblessed); # will be removed.
426 3         9 return 'null';
427             }
428 2         17 encode_error( sprintf("encountered object '%s', but neither allow_blessed, convert_blessed nor allow_tags settings are enabled (or TO_JSON/FREEZE method missing)", $obj)
429             );
430             }
431             else {
432 20         68 return $self->value_to_json($obj);
433             }
434             }
435             else{
436 81         186 return $self->value_to_json($obj);
437             }
438             }
439              
440              
441             sub hash_to_json {
442 346     346 0 617 my ($self, $obj) = @_;
443 346         455 my @res;
444              
445 346 100       660 encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
446             if (++$depth > $max_depth);
447              
448 345 100       848 my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
449 345 100       921 my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : '');
    100          
450              
451 345         673 for my $k ( _sort( $obj ) ) {
452             push @res, $self->string_to_json( $k )
453             . $del
454 744 100       1488 . ( ref $obj->{$k} ? $self->object_to_json( $obj->{$k} ) : $self->value_to_json( $obj->{$k} ) );
455             }
456              
457 343         570 --$depth;
458 343 100       619 $self->_down_indent() if ($indent);
459              
460 343 100       685 return '{}' unless @res;
461 333         1670 return '{' . $pre . join( ",$pre", @res ) . $post . '}';
462             }
463              
464              
465             sub array_to_json {
466 25010     25010 0 43248 my ($self, $obj) = @_;
467 25010         37981 my @res;
468              
469 25010 100       56998 encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
470             if (++$depth > $max_depth);
471              
472 25009 100       62207 my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
473              
474 25009         50512 for my $v (@$obj){
475 25795 100       72942 push @res, ref($v) ? $self->object_to_json($v) : $self->value_to_json($v);
476             }
477              
478 24995         44216 --$depth;
479 24995 100       50922 $self->_down_indent() if ($indent);
480              
481 24995 100       61701 return '[]' unless @res;
482 24985         207662 return '[' . $pre . join( ",$pre", @res ) . $post . ']';
483             }
484              
485             sub _looks_like_number {
486 26230     26230   41246 my $value = shift;
487 26230         34537 if (USE_B) {
488             my $b_obj = B::svref_2object(\$value);
489             my $flags = $b_obj->FLAGS;
490             return 1 if $flags & ( B::SVp_IOK() | B::SVp_NOK() ) and !( $flags & B::SVp_POK() );
491             return;
492             } else {
493 64     64   605 no warnings 'numeric';
  64         267  
  64         10814  
494             # if the utf8 flag is on, it almost certainly started as a string
495 26230 100       92124 return if utf8::is_utf8($value);
496             # detect numbers
497             # string & "" -> ""
498             # number & "" -> 0 (with warning)
499             # nan and inf can detect as numbers, so check with * 0
500 13743 100       63524 return unless length((my $dummy = "") & $value);
501 817 100       1815 return unless 0 + $value eq $value;
502 816 50       2302 return 1 if $value * 0 == 0;
503 0         0 return -1; # inf/nan
504             }
505             }
506              
507             sub value_to_json {
508 26314     26314 0 47209 my ($self, $value) = @_;
509              
510 26314 100       56562 return 'null' if(!defined $value);
511              
512 26270         43409 my $type = ref($value);
513              
514 26270 100 66     50765 if (!$type) {
    100          
515 64     64   75084 BEGIN { CORE_BOOL and warnings->unimport('experimental::builtin') }
516 26230 100       55412 if (CORE_BOOL && builtin::is_bool($value)) {
517             return $value ? 'true' : 'false';
518             }
519 0         0 elsif (_looks_like_number($value)) {
520 816         2309 return $value;
521             }
522 25414         70845 return $self->string_to_json($value);
523             }
524             elsif( blessed($value) and $value->isa('JSON::PP::Boolean') ){
525 20 100       157 return $$value == 1 ? 'true' : 'false';
526             }
527             else {
528 20 50       59 if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
529 0         0 return $self->value_to_json("$value");
530             }
531              
532 20 100 100     185 if ($type eq 'SCALAR' and defined $$value) {
533             return $$value eq '1' ? 'true'
534             : $$value eq '0' ? 'false'
535 7 100       58 : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
    100          
    100          
536             : encode_error("cannot encode reference to scalar");
537             }
538              
539 13 100       33 if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
540 4         14 return 'null';
541             }
542             else {
543 9 100 100     40 if ( $type eq 'SCALAR' or $type eq 'REF' ) {
544 6         13 encode_error("cannot encode reference to scalar");
545             }
546             else {
547 3         16 encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
548             }
549             }
550              
551             }
552             }
553              
554              
555             my %esc = (
556             "\n" => '\n',
557             "\r" => '\r',
558             "\t" => '\t',
559             "\f" => '\f',
560             "\b" => '\b',
561             "\"" => '\"',
562             "\\" => '\\\\',
563             "\'" => '\\\'',
564             );
565              
566              
567             sub string_to_json {
568 26158     26158 0 59041 my ($self, $arg) = @_;
569              
570 26158         500359 $arg =~ s/(["\\\n\r\t\f\b])/$esc{$1}/g;
571 26158 100       65096 $arg =~ s/\//\\\//g if ($escape_slash);
572              
573             # On ASCII platforms, matches [\x00-\x08\x0b\x0e-\x1f]
574 26158         172849 $arg =~ s/([^\n\t\c?[:^cntrl:][:^ascii:]])/'\\u00' . unpack('H2', $1)/eg;
  578676         1604771  
575              
576 26158 100       63643 if ($ascii) {
577 12297         35484 $arg = _encode_ascii($arg);
578             }
579              
580 26158 100       188899 if ($latin1) {
581 2         5 $arg = _encode_latin1($arg);
582             }
583              
584 26158 100       52184 if ($utf8) {
585 12551         54119 utf8::encode($arg);
586             }
587              
588 26158         246454 return '"' . $arg . '"';
589             }
590              
591              
592             sub blessed_to_json {
593 0   0 0 0 0 my $reftype = reftype($_[1]) || '';
594 0 0       0 if ($reftype eq 'HASH') {
    0          
595 0         0 return $_[0]->hash_to_json($_[1]);
596             }
597             elsif ($reftype eq 'ARRAY') {
598 0         0 return $_[0]->array_to_json($_[1]);
599             }
600             else {
601 0         0 return 'null';
602             }
603             }
604              
605              
606             sub encode_error {
607 18     18 0 73 my $error = shift;
608 18         2455 Carp::croak "$error";
609             }
610              
611              
612             sub _sort {
613 345 100   345   613 defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]};
  222         1126  
  123         494  
614             }
615              
616              
617             sub _up_indent {
618 9     9   13 my $self = shift;
619 9         17 my $space = ' ' x $indent_length;
620              
621 9         14 my ($pre,$post) = ('','');
622              
623 9         19 $post = "\n" . $space x $indent_count;
624              
625 9         10 $indent_count++;
626              
627 9         12 $pre = "\n" . $space x $indent_count;
628              
629 9         24 return ($pre,$post);
630             }
631              
632              
633 9     9   11 sub _down_indent { $indent_count--; }
634              
635              
636             sub PP_encode_box {
637             {
638 0     0 0 0 depth => $depth,
639             indent_count => $indent_count,
640             };
641             }
642              
643             } # Convert
644              
645              
646             sub _encode_ascii {
647             join('',
648             map {
649 12297 100   12297   354555 chr($_) =~ /[[:ascii:]]/ ?
  6259537 100       16213280  
650             chr($_) :
651             $_ <= 65535 ?
652             sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
653             } unpack('U*', $_[0])
654             );
655             }
656              
657              
658             sub _encode_latin1 {
659             join('',
660             map {
661 2 50   2   10 $_ <= 255 ?
  22 100       73  
662             chr($_) :
663             $_ <= 65535 ?
664             sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
665             } unpack('U*', $_[0])
666             );
667             }
668              
669              
670             sub _encode_surrogates { # from perlunicode
671 1127975     1127975   1439492 my $uni = $_[0] - 0x10000;
672 1127975         3241723 return ($uni / 0x400 + 0xD800, $uni % 0x400 + 0xDC00);
673             }
674              
675              
676             sub _is_bignum {
677 3 100   3   19 $_[0]->isa('Math::BigInt') or $_[0]->isa('Math::BigFloat');
678             }
679              
680              
681              
682             #
683             # JSON => Perl
684             #
685              
686             my $max_intsize;
687              
688             BEGIN {
689 64     64   288 my $checkint = 1111;
690 64         365 for my $d (5..64) {
691 1088         1836 $checkint .= 1;
692 1088         34473 my $int = eval qq| $checkint |;
693 1088 100       5505 if ($int =~ /[eE]/) {
694 64         182 $max_intsize = $d - 1;
695 64         28976 last;
696             }
697             }
698             }
699              
700             { # PARSE
701              
702             my %escapes = ( # by Jeremy Muhlich
703             b => "\b",
704             t => "\t",
705             n => "\n",
706             f => "\f",
707             r => "\r",
708             '\\' => '\\',
709             '"' => '"',
710             '/' => '/',
711             );
712              
713             my $text; # json data
714             my $at; # offset
715             my $ch; # first character
716             my $len; # text length (changed according to UTF8 or NON UTF8)
717             # INTERNAL
718             my $depth; # nest counter
719             my $encoding; # json text encoding
720             my $is_valid_utf8; # temp variable
721             my $utf8_len; # utf8 byte length
722             # FLAGS
723             my $utf8; # must be utf8
724             my $max_depth; # max nest number of objects and arrays
725             my $max_size;
726             my $relaxed;
727             my $cb_object;
728             my $cb_sk_object;
729              
730             my $F_HOOK;
731              
732             my $allow_bignum; # using Math::BigInt/BigFloat
733             my $singlequote; # loosely quoting
734             my $loose; #
735             my $allow_barekey; # bareKey
736             my $allow_tags;
737              
738             my $alt_true;
739             my $alt_false;
740              
741             sub _detect_utf_encoding {
742 12410     12410   23740 my $text = shift;
743 12410         43840 my @octets = unpack('C4', $text);
744 12410 100       30494 return 'unknown' unless defined $octets[3];
745 12390 0 100     56491 return ( $octets[0] and $octets[1]) ? 'UTF-8'
    50 66        
    50 33        
    100          
    100          
746             : (!$octets[0] and $octets[1]) ? 'UTF-16BE'
747             : (!$octets[0] and !$octets[1]) ? 'UTF-32BE'
748             : ( $octets[2] ) ? 'UTF-16LE'
749             : (!$octets[2] ) ? 'UTF-32LE'
750             : 'unknown';
751             }
752              
753             sub PP_decode_json {
754 25269     25269 0 43392 my ($self, $want_offset);
755              
756 25269         67833 ($self, $text, $want_offset) = @_;
757              
758 25269         51918 ($at, $ch, $depth) = (0, '', 0);
759              
760 25269 100 100     108959 if ( !defined $text or ref $text ) {
761 4         11 decode_error("malformed JSON string, neither array, object, number, string or atom");
762             }
763              
764 25265         46936 my $props = $self->{PROPS};
765              
766             ($utf8, $relaxed, $loose, $allow_bignum, $allow_barekey, $singlequote, $allow_tags)
767 25265         47315 = @{$props}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE, P_ALLOW_TAGS];
  25265         69487  
768              
769 25265         60974 ($alt_true, $alt_false) = @$self{qw/true false/};
770              
771 25265 100       48183 if ( $utf8 ) {
772 12410         29118 $encoding = _detect_utf_encoding($text);
773 12410 100 100     40362 if ($encoding ne 'UTF-8' and $encoding ne 'unknown') {
774 3         633 require Encode;
775 3         10610 Encode::from_to($text, $encoding, 'utf-8');
776             } else {
777 12407 100       40645 utf8::downgrade( $text, 1 ) or Carp::croak("Wide character in subroutine entry");
778             }
779             }
780             else {
781 12855         61463 utf8::encode( $text );
782             }
783              
784 25264         43743 $len = length $text;
785              
786             ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK)
787 25264         38889 = @{$self}{qw/max_depth max_size cb_object cb_sk_object F_HOOK/};
  25264         66171  
788              
789 25264 100       56970 if ($max_size > 1) {
790 64     64   41964 use bytes;
  64         941  
  64         361  
791 2         3 my $bytes = length $text;
792 2 100       13 decode_error(
793             sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s"
794             , $bytes, $max_size), 1
795             ) if ($bytes > $max_size);
796             }
797              
798 25263         62497 white(); # remove head white space
799              
800 25263 100       54030 decode_error("malformed JSON string, neither array, object, number, string or atom") unless defined $ch; # Is there a first character for JSON structure?
801              
802 25261         48534 my $result = value();
803              
804 25184 100 100     98322 if ( !$props->[ P_ALLOW_NONREF ] and !ref $result ) {
805 5         31 decode_error(
806             'JSON text must be an object or array (but found number, string, true, false or null,'
807             . ' use allow_nonref to allow this)', 1);
808             }
809              
810 25179 50       54732 Carp::croak('something wrong.') if $len < $at; # we won't arrive here.
811              
812 25179 100       53529 my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length
813              
814 25179         50855 white(); # remove tail white space
815              
816 25179 100       49252 return ( $result, $consumed ) if $want_offset; # all right if decode_prefix
817              
818 24875 100       44138 decode_error("garbage after JSON object") if defined $ch;
819              
820 24863         215409 $result;
821             }
822              
823              
824             sub next_chr {
825 36720055 100   36720055 0 55253745 return $ch = undef if($at >= $len);
826 36694985         64699704 $ch = substr($text, $at++, 1);
827             }
828              
829              
830             sub value {
831 53833     53833 0 100576 white();
832 53833 50       95919 return if(!defined $ch);
833 53833 100       99294 return object() if($ch eq '{');
834 52443 100       109352 return array() if($ch eq '[');
835 26328 100       51029 return tag() if($ch eq '(');
836 26327 100 66     80145 return string() if($ch eq '"' or ($singlequote and $ch eq "'"));
      100        
837 905 100 100     3114 return number() if($ch =~ /[0-9]/ or $ch eq '-');
838 93         193 return word();
839             }
840              
841             sub string {
842 27152     27152 1 42049 my $utf16;
843             my $is_utf8;
844              
845 27152         50718 ($is_valid_utf8, $utf8_len) = ('', 0);
846              
847 27152         41360 my $s = ''; # basically UTF8 flag on
848              
849 27152 100 66     57797 if($ch eq '"' or ($singlequote and $ch eq "'")){
      100        
850 27147         37285 my $boundChar = $ch;
851              
852 27147         42627 OUTER: while( defined(next_chr()) ){
853              
854 10715493 100       20702781 if($ch eq $boundChar){
    100          
855 27131         62880 next_chr();
856              
857 27131 100       50311 if ($utf16) {
858 1         2 decode_error("missing low surrogate character in surrogate pair");
859             }
860              
861 27130 100       137333 utf8::decode($s) if($is_utf8);
862              
863 27130         137827 return $s;
864             }
865             elsif($ch eq '\\'){
866 5300299         8944633 next_chr();
867 5300299 100       9306862 if(exists $escapes{$ch}){
    100          
868 152492         259915 $s .= $escapes{$ch};
869             }
870             elsif($ch eq 'u'){ # UNICODE handling
871 5147803         6217429 my $u = '';
872              
873 5147803         7528702 for(1..4){
874 20591212         27019233 $ch = next_chr();
875 20591212 50       46856319 last OUTER if($ch !~ /[0-9a-fA-F]/);
876 20591212         30025788 $u .= $ch;
877             }
878              
879             # U+D800 - U+DBFF
880 5147803 100       11501569 if ($u =~ /^[dD][89abAB][0-9a-fA-F]{2}/) { # UTF-16 high surrogate?
    100          
881 1127978         1975522 $utf16 = $u;
882             }
883             # U+DC00 - U+DFFF
884             elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate?
885 1127977 100       1792823 unless (defined $utf16) {
886 1         3 decode_error("missing high surrogate character in surrogate pair");
887             }
888 1127976         1307917 $is_utf8 = 1;
889 1127976   50     1669905 $s .= _decode_surrogates($utf16, $u) || next;
890 1127976         2138174 $utf16 = undef;
891             }
892             else {
893 2891848 100       4574227 if (defined $utf16) {
894 1         3 decode_error("surrogate pair expected");
895             }
896              
897 2891847         3888444 my $hex = hex( $u );
898 2891847 50       4759325 if ( chr $u =~ /[[:^ascii:]]/ ) {
899 2891847         3309226 $is_utf8 = 1;
900 2891847   50     4134326 $s .= _decode_unicode($u) || next;
901             }
902             else {
903 0         0 $s .= chr $hex;
904             }
905             }
906              
907             }
908             else{
909 4 50       7 unless ($loose) {
910 4         7 $at -= 2;
911 4         7 decode_error('illegal backslash escape sequence in string');
912             }
913 0         0 $s .= $ch;
914             }
915             }
916             else{
917              
918 5388063 100       11137169 if ( $ch =~ /[[:^ascii:]]/ ) {
919 3441000 100       4966551 unless( $ch = is_valid_utf8($ch) ) {
920 5         9 $at -= 1;
921 5         24 decode_error("malformed UTF-8 character in JSON string");
922             }
923             else {
924 3440995         4760198 $at += $utf8_len - 1;
925             }
926              
927 3440995         4377535 $is_utf8 = 1;
928             }
929              
930 5388058 50       8191713 if (!$loose) {
931 5388058 100       14756393 if ($ch =~ $invalid_char_re) { # '/' ok
932 4 50 33     16 if (!$relaxed or $ch ne "\t") {
933 4         6 $at--;
934 4         38 decode_error(sprintf "invalid character 0x%X"
935             . " encountered while parsing JSON string",
936             ord $ch);
937             }
938             }
939             }
940              
941 5388054         8993357 $s .= $ch;
942             }
943             }
944             }
945              
946 6         21 decode_error("unexpected end of string while parsing JSON string");
947             }
948              
949              
950             sub white {
951 162105     162105 0 289658 while( defined $ch ){
952 164722 100 100     610868 if($ch eq '' or $ch =~ /\A[ \t\r\n]\z/){
    50 66        
953 27669         47055 next_chr();
954             }
955             elsif($relaxed and $ch eq '/'){
956 0         0 next_chr();
957 0 0 0     0 if(defined $ch and $ch eq '/'){
    0 0        
958 0   0     0 1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
      0        
959             }
960             elsif(defined $ch and $ch eq '*'){
961 0         0 next_chr();
962 0         0 while(1){
963 0 0       0 if(defined $ch){
964 0 0       0 if($ch eq '*'){
965 0 0 0     0 if(defined(next_chr()) and $ch eq '/'){
966 0         0 next_chr();
967 0         0 last;
968             }
969             }
970             else{
971 0         0 next_chr();
972             }
973             }
974             else{
975 0         0 decode_error("Unterminated comment");
976             }
977             }
978 0         0 next;
979             }
980             else{
981 0         0 $at--;
982 0         0 decode_error("malformed JSON string, neither array, object, number, string or atom");
983             }
984             }
985             else{
986 137053 100 100     251635 if ($relaxed and $ch eq '#') { # correctly?
987 9         24 pos($text) = $at;
988 9         38 $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g;
989 9         15 $at = pos($text);
990 9         28 next_chr;
991 9         15 next;
992             }
993              
994 137044         190514 last;
995             }
996             }
997             }
998              
999              
1000             sub array {
1001 26115   50 26115 1 88154 my $a = $_[0] || []; # you can use this code to use another array ref object.
1002              
1003 26115 100       58642 decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
1004             if (++$depth > $max_depth);
1005              
1006 26112         51720 next_chr();
1007 26112         53291 white();
1008              
1009 26112 100 66     90089 if(defined $ch and $ch eq ']'){
1010 23         48 --$depth;
1011 23         57 next_chr();
1012 23         61 return $a;
1013             }
1014             else {
1015 26089         52154 while(defined($ch)){
1016 26846         56106 push @$a, value();
1017              
1018 26279         66704 white();
1019              
1020 26279 100       55422 if (!defined $ch) {
1021 3         8 last;
1022             }
1023              
1024 26276 100       55959 if($ch eq ']'){
1025 25514         37522 --$depth;
1026 25514         52940 next_chr();
1027 25514         64400 return $a;
1028             }
1029              
1030 762 100       1331 if($ch ne ','){
1031 3         4 last;
1032             }
1033              
1034 759         1369 next_chr();
1035 759         1386 white();
1036              
1037 759 100 100     1807 if ($relaxed and $ch eq ']') {
1038 2         4 --$depth;
1039 2         6 next_chr();
1040 2         5 return $a;
1041             }
1042              
1043             }
1044             }
1045              
1046 6 100 66     36 $at-- if defined $ch and $ch ne '';
1047 6         19 decode_error(", or ] expected while parsing array");
1048             }
1049              
1050             sub tag {
1051 1 50   1 0 4 decode_error('malformed JSON string, neither array, object, number, string or atom') unless $allow_tags;
1052              
1053 1         2 next_chr();
1054 1         3 white();
1055              
1056 1         4 my $tag = value();
1057 1 50       4 return unless defined $tag;
1058 1 50       2 decode_error('malformed JSON string, (tag) must be a string') if ref $tag;
1059              
1060 1         4 white();
1061              
1062 1 50 33     6 if (!defined $ch or $ch ne ')') {
1063 0         0 decode_error(') expected after tag');
1064             }
1065              
1066 1         3 next_chr();
1067 1         2 white();
1068              
1069 1         2 my $val = value();
1070 1 50       4 return unless defined $val;
1071 1 50       5 decode_error('malformed JSON string, tag value must be an array') unless ref $val eq 'ARRAY';
1072              
1073 1 50       3 if (!eval { $tag->can('THAW') }) {
  1         8  
1074 0 0       0 decode_error('cannot decode perl-object (package does not exist)') if $@;
1075 0         0 decode_error('cannot decode perl-object (package does not have a THAW method)');
1076             }
1077 1         8 $tag->THAW('JSON', @$val);
1078             }
1079              
1080             sub object {
1081 1390   50 1390 1 3939 my $o = $_[0] || {}; # you can use this code to use another hash ref object.
1082 1390         1909 my $k;
1083              
1084 1390 50       2451 decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
1085             if (++$depth > $max_depth);
1086 1390         2538 next_chr();
1087 1390         2422 white();
1088              
1089 1390 100 66     3752 if(defined $ch and $ch eq '}'){
1090 9         27 --$depth;
1091 9         40 next_chr();
1092 9 100       22 if ($F_HOOK) {
1093 1         4 return _json_object_hook($o);
1094             }
1095 8         91 return $o;
1096             }
1097             else {
1098 1381         2344 while (defined $ch) {
1099 1732 100 66     4314 $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string();
1100 1727         3225 white();
1101              
1102 1727 100 100     4931 if(!defined $ch or $ch ne ':'){
1103 3         6 $at--;
1104 3         8 decode_error("':' expected");
1105             }
1106              
1107 1724         3305 next_chr();
1108 1724         3775 $o->{$k} = value();
1109 1207         2421 white();
1110              
1111 1207 100       2084 last if (!defined $ch);
1112              
1113 1205 100       2067 if($ch eq '}'){
1114 847         989 --$depth;
1115 847         1582 next_chr();
1116 847 100       1370 if ($F_HOOK) {
1117 8         18 return _json_object_hook($o);
1118             }
1119 839         2454 return $o;
1120             }
1121              
1122 358 100       695 if($ch ne ','){
1123 5         9 last;
1124             }
1125              
1126 353         734 next_chr();
1127 353         626 white();
1128              
1129 353 100 66     898 if ($relaxed and $ch eq '}') {
1130 1         2 --$depth;
1131 1         4 next_chr();
1132 1 50       2 if ($F_HOOK) {
1133 0         0 return _json_object_hook($o);
1134             }
1135 1         3 return $o;
1136             }
1137              
1138             }
1139              
1140             }
1141              
1142 8 100 66     72 $at-- if defined $ch and $ch ne '';
1143 8         38 decode_error(", or } expected while parsing object/hash");
1144             }
1145              
1146              
1147             sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition
1148 2     2 0 5 my $key;
1149 2         11 while($ch =~ /[\$\w[:^ascii:]]/){
1150 6         10 $key .= $ch;
1151 6         12 next_chr();
1152             }
1153 2         6 return $key;
1154             }
1155              
1156              
1157             sub word {
1158 93     93 0 199 my $word = substr($text,$at-1,4);
1159              
1160 93 100       304 if($word eq 'true'){
    100          
    100          
1161 14         30 $at += 3;
1162 14         31 next_chr;
1163 14 100       57 return defined $alt_true ? $alt_true : $JSON::PP::true;
1164             }
1165             elsif($word eq 'null'){
1166 44         74 $at += 3;
1167 44         146 next_chr;
1168 44         134 return undef;
1169             }
1170             elsif($word eq 'fals'){
1171 11         20 $at += 3;
1172 11 50       32 if(substr($text,$at,1) eq 'e'){
1173 11         34 $at++;
1174 11         32 next_chr;
1175 11 100       33 return defined $alt_false ? $alt_false : $JSON::PP::false;
1176             }
1177             }
1178              
1179 24         35 $at--; # for decode_error report
1180              
1181 24 100       116 decode_error("'null' expected") if ($word =~ /^n/);
1182 23 100       55 decode_error("'true' expected") if ($word =~ /^t/);
1183 22 50       49 decode_error("'false' expected") if ($word =~ /^f/);
1184 22         50 decode_error("malformed JSON string, neither array, object, number, string or atom");
1185             }
1186              
1187              
1188             sub number {
1189 812     812 1 1259 my $n = '';
1190 812         1653 my $v;
1191             my $is_dec;
1192 812         0 my $is_exp;
1193              
1194 812 100       1508 if($ch eq '-'){
1195 41         79 $n = '-';
1196 41         89 next_chr;
1197 41 100 66     993 if (!defined $ch or $ch !~ /\d/) {
1198 1         4 decode_error("malformed number (no digits after initial minus)");
1199             }
1200             }
1201              
1202             # According to RFC4627, hex or oct digits are invalid.
1203 811 100       1565 if($ch eq '0'){
1204 46         103 my $peek = substr($text,$at,1);
1205 46 100       125 if($peek =~ /^[0-9a-dfA-DF]/){ # e may be valid (exponential)
1206 5         13 decode_error("malformed number (leading zero must not be followed by another digit)");
1207             }
1208 41         67 $n .= $ch;
1209 41         63 next_chr;
1210             }
1211              
1212 806   100     3063 while(defined $ch and $ch =~ /\d/){
1213 971         1467 $n .= $ch;
1214 971         1458 next_chr;
1215             }
1216              
1217 806 100 100     2417 if(defined $ch and $ch eq '.'){
1218 49         120 $n .= '.';
1219 49         76 $is_dec = 1;
1220              
1221 49         103 next_chr;
1222 49 100 66     205 if (!defined $ch or $ch !~ /\d/) {
1223 1         3 decode_error("malformed number (no digits after decimal point)");
1224             }
1225             else {
1226 48         83 $n .= $ch;
1227             }
1228              
1229 48   100     83 while(defined(next_chr) and $ch =~ /\d/){
1230 97         183 $n .= $ch;
1231             }
1232             }
1233              
1234 805 100 100     3173 if(defined $ch and ($ch eq 'e' or $ch eq 'E')){
      100        
1235 58         88 $n .= $ch;
1236 58         76 $is_exp = 1;
1237 58         117 next_chr;
1238              
1239 58 100 100     292 if(defined($ch) and ($ch eq '+' or $ch eq '-')){
    100 100        
      100        
1240 38         71 $n .= $ch;
1241 38         89 next_chr;
1242 38 100 66     157 if (!defined $ch or $ch =~ /\D/) {
1243 2         5 decode_error("malformed number (no digits after exp sign)");
1244             }
1245 36         58 $n .= $ch;
1246             }
1247             elsif(defined($ch) and $ch =~ /\d/){
1248 18         31 $n .= $ch;
1249             }
1250             else {
1251 2         6 decode_error("malformed number (no digits after exp sign)");
1252             }
1253              
1254 54   100     89 while(defined(next_chr) and $ch =~ /\d/){
1255 33         76 $n .= $ch;
1256             }
1257              
1258             }
1259              
1260 801         1179 $v .= $n;
1261              
1262 801 100 100     2131 if ($is_dec or $is_exp) {
1263 70 100       134 if ($allow_bignum) {
1264 1         1247 require Math::BigFloat;
1265 1         28018 return Math::BigFloat->new($v);
1266             }
1267             } else {
1268 731 100       1357 if (length $v > $max_intsize) {
1269 1 50       3 if ($allow_bignum) { # from Adam Sussman
1270 1         9 require Math::BigInt;
1271 1         5 return Math::BigInt->new($v);
1272             }
1273             else {
1274 0         0 return "$v";
1275             }
1276             }
1277             }
1278              
1279 799 100       2622 return $is_dec ? $v/1.0 : 0+$v;
1280             }
1281              
1282             # Compute how many bytes are in the longest legal official Unicode
1283             # character
1284             my $max_unicode_length = do {
1285 64     64   178904 no warnings 'utf8';
  64         156  
  64         67857  
1286             chr 0x10FFFF;
1287             };
1288             utf8::encode($max_unicode_length);
1289             $max_unicode_length = length $max_unicode_length;
1290              
1291             sub is_valid_utf8 {
1292              
1293             # Returns undef (setting $utf8_len to 0) unless the next bytes in $text
1294             # comprise a well-formed UTF-8 encoded character, in which case,
1295             # return those bytes, setting $utf8_len to their count.
1296              
1297 3441000     3441000 0 6732802 my $start_point = substr($text, $at - 1);
1298              
1299             # Look no further than the maximum number of bytes in a single
1300             # character
1301 3441000         4259232 my $limit = $max_unicode_length;
1302 3441000 100       5499261 $limit = length($start_point) if $limit > length($start_point);
1303              
1304             # Find the number of bytes comprising the first character in $text
1305             # (without having to know the details of its internal representation).
1306             # This loop will iterate just once on well-formed input.
1307 3441000         5481138 while ($limit > 0) { # Until we succeed or exhaust the input
1308 4681125         6174040 my $copy = substr($start_point, 0, $limit);
1309              
1310             # decode() will return true if all bytes are valid; false
1311             # if any aren't.
1312 4681125 100       8527846 if (utf8::decode($copy)) {
1313              
1314             # Is valid: get the first character, convert back to bytes,
1315             # and return those bytes.
1316 3440995         7010027 $copy = substr($copy, 0, 1);
1317 3440995         6526663 utf8::encode($copy);
1318 3440995         3944397 $utf8_len = length $copy;
1319 3440995         8019551 return substr($start_point, 0, $utf8_len);
1320             }
1321              
1322             # If it didn't work, it could be that there is a full legal character
1323             # followed by a partial or malformed one. Narrow the window and
1324             # try again.
1325 1240130         2023886 $limit--;
1326             }
1327              
1328             # Failed to find a legal UTF-8 character.
1329 5         15 $utf8_len = 0;
1330 5         26 return;
1331             }
1332              
1333              
1334             sub decode_error {
1335 101     101 0 211 my $error = shift;
1336 101         151 my $no_rep = shift;
1337 101 100       273 my $str = defined $text ? substr($text, $at) : '';
1338 101         179 my $mess = '';
1339 101         156 my $type = 'U*';
1340              
1341 101         572 for my $c ( unpack( $type, $str ) ) { # emulate pv_uni_display() ?
1342 459         749 my $chr_c = chr($c);
1343 459 50       1420 $mess .= $chr_c eq '\\' ? '\\\\'
    50          
    50          
    50          
    50          
    100          
    100          
1344             : $chr_c =~ /[[:print:]]/ ? $chr_c
1345             : $chr_c eq '\a' ? '\a'
1346             : $chr_c eq '\t' ? '\t'
1347             : $chr_c eq '\n' ? '\n'
1348             : $chr_c eq '\r' ? '\r'
1349             : $chr_c eq '\f' ? '\f'
1350             : sprintf('\x{%x}', $c)
1351             ;
1352 459 100       959 if ( length $mess >= 20 ) {
1353 10         22 $mess .= '...';
1354 10         33 last;
1355             }
1356             }
1357              
1358 101 100       335 unless ( length $mess ) {
1359 30         55 $mess = '(end of string)';
1360             }
1361              
1362             Carp::croak (
1363 101 100       35587 $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")"
1364             );
1365              
1366             }
1367              
1368              
1369             sub _json_object_hook {
1370 9     9   16 my $o = $_[0];
1371 9         12 my @ks = keys %{$o};
  9         31  
1372              
1373 9 100 66     53 if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) {
      100        
      66        
1374 4         13 my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} );
1375 4 100       19 if (@val == 0) {
    50          
1376 1         3 return $o;
1377             }
1378             elsif (@val == 1) {
1379 3         13 return $val[0];
1380             }
1381             else {
1382 0         0 Carp::croak("filter_json_single_key_object callbacks must not return more than one scalar");
1383             }
1384             }
1385              
1386 5 100       14 my @val = $cb_object->($o) if ($cb_object);
1387 5 100       19 if (@val == 0) {
    50          
1388 3         41 return $o;
1389             }
1390             elsif (@val == 1) {
1391 2         9 return $val[0];
1392             }
1393             else {
1394 0         0 Carp::croak("filter_json_object callbacks must not return more than one scalar");
1395             }
1396             }
1397              
1398              
1399             sub PP_decode_box {
1400             {
1401 0     0 0 0 text => $text,
1402             at => $at,
1403             ch => $ch,
1404             len => $len,
1405             depth => $depth,
1406             encoding => $encoding,
1407             is_valid_utf8 => $is_valid_utf8,
1408             };
1409             }
1410              
1411             } # PARSE
1412              
1413              
1414             sub _decode_surrogates { # from perlunicode
1415 1127976     1127976   2013628 my $uni = 0x10000 + (hex($_[0]) - 0xD800) * 0x400 + (hex($_[1]) - 0xDC00);
1416 1127976         2125319 my $un = pack('U*', $uni);
1417 1127976         2136242 utf8::encode( $un );
1418 1127976         2333278 return $un;
1419             }
1420              
1421              
1422             sub _decode_unicode {
1423 2891847     2891847   5264019 my $un = pack('U', hex shift);
1424 2891847         5408234 utf8::encode( $un );
1425 2891847         7782288 return $un;
1426             }
1427              
1428             sub incr_parse {
1429 744     744 1 51917 local $Carp::CarpLevel = 1;
1430 744   66     2404 ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_parse( @_ );
1431             }
1432              
1433              
1434             sub incr_skip {
1435 2   33 2 1 1669 ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_skip;
1436             }
1437              
1438              
1439             sub incr_reset {
1440 0   0 0 1 0 ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_reset;
1441             }
1442              
1443             sub incr_text : lvalue {
1444 304   33 304 1 39728 $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new;
1445              
1446 304 50       686 if ( $_[0]->{_incr_parser}->{incr_pos} ) {
1447 0         0 Carp::croak("incr_text cannot be called when the incremental parser already started parsing");
1448             }
1449 304         1836 $_[0]->{_incr_parser}->{incr_text};
1450             }
1451              
1452              
1453             ###############################
1454             # Utilities
1455             #
1456              
1457             # shamelessly copied and modified from JSON::XS code.
1458              
1459             $JSON::PP::true = do { bless \(my $dummy = 1), "JSON::PP::Boolean" };
1460             $JSON::PP::false = do { bless \(my $dummy = 0), "JSON::PP::Boolean" };
1461              
1462             sub is_bool {
1463 5 100   5 1 858 if (blessed $_[0]) {
1464             return (
1465 2   33     32 $_[0]->isa("JSON::PP::Boolean")
1466             or $_[0]->isa("Types::Serialiser::BooleanBase")
1467             or $_[0]->isa("JSON::XS::Boolean")
1468             );
1469             }
1470 0         0 elsif (CORE_BOOL) {
1471 64     64   8145 BEGIN { CORE_BOOL and warnings->unimport('experimental::builtin') }
1472             return builtin::is_bool($_[0]);
1473             }
1474 3         13 return !!0;
1475             }
1476              
1477 3     3 1 586 sub true { $JSON::PP::true }
1478 3     3 1 14 sub false { $JSON::PP::false }
1479 0     0 1 0 sub null { undef; }
1480              
1481             ###############################
1482              
1483             package JSON::PP::IncrParser;
1484              
1485 64     64   516 use strict;
  64         170  
  64         2048  
1486              
1487 64     64   360 use constant INCR_M_WS => 0; # initial whitespace skipping
  64         1591  
  64         4733  
1488 64     64   426 use constant INCR_M_STR => 1; # inside string
  64         195  
  64         3618  
1489 64     64   404 use constant INCR_M_BS => 2; # inside backslash
  64         155  
  64         3379  
1490 64     64   441 use constant INCR_M_JSON => 3; # outside anything, count nesting
  64         149  
  64         3379  
1491 64     64   460 use constant INCR_M_C0 => 4;
  64         177  
  64         3558  
1492 64     64   1130 use constant INCR_M_C1 => 5;
  64         167  
  64         3373  
1493 64     64   426 use constant INCR_M_TFN => 6;
  64         197  
  64         3434  
1494 64     64   450 use constant INCR_M_NUM => 7;
  64         148  
  64         21964  
1495              
1496             our $VERSION = '1.01';
1497              
1498             sub new {
1499 57     57   124 my ( $class ) = @_;
1500              
1501 57         367 bless {
1502             incr_nest => 0,
1503             incr_text => undef,
1504             incr_pos => 0,
1505             incr_mode => 0,
1506             }, $class;
1507             }
1508              
1509              
1510             sub incr_parse {
1511 744     744   1345 my ( $self, $coder, $text ) = @_;
1512              
1513 744 100       1484 $self->{incr_text} = '' unless ( defined $self->{incr_text} );
1514              
1515 744 100       1297 if ( defined $text ) {
1516 402         926 $self->{incr_text} .= $text;
1517             }
1518              
1519 744 100       2042 if ( defined wantarray ) {
1520 383         863 my $max_size = $coder->get_max_size;
1521 383         583 my $p = $self->{incr_pos};
1522 383         594 my @ret;
1523             {
1524 383         481 do {
  383         516  
1525 394 100 100     1417 unless ( $self->{incr_nest} <= 0 and $self->{incr_mode} == INCR_M_JSON ) {
1526 393         974 $self->_incr_parse( $coder );
1527              
1528 392 100 100     901 if ( $max_size and $self->{incr_pos} > $max_size ) {
1529 1         100 Carp::croak("attempted decode of JSON text of $self->{incr_pos} bytes size, but max_size is set to $max_size");
1530             }
1531 391 100 100     1240 unless ( $self->{incr_nest} <= 0 and $self->{incr_mode} == INCR_M_JSON ) {
1532             # as an optimisation, do not accumulate white space in the incr buffer
1533 83 100 100     257 if ( $self->{incr_mode} == INCR_M_WS and $self->{incr_pos} ) {
1534 7         10 $self->{incr_pos} = 0;
1535 7         57 $self->{incr_text} = '';
1536             }
1537 83         155 last;
1538             }
1539             }
1540              
1541 309 100       7798 unless ( $coder->get_utf8 ) {
1542 301         1010 utf8::decode( $self->{incr_text} );
1543             }
1544              
1545 309         845 my ($obj, $offset) = $coder->PP_decode_json( $self->{incr_text}, 0x00000001 );
1546 298         543 push @ret, $obj;
1547 64     64   511 use bytes;
  64         198  
  64         318  
1548 298   50     960 $self->{incr_text} = substr( $self->{incr_text}, $offset || 0 );
1549 298         434 $self->{incr_pos} = 0;
1550 298         539 $self->{incr_nest} = 0;
1551 298         380 $self->{incr_mode} = 0;
1552 298 100       692 last unless wantarray;
1553             } while ( wantarray );
1554             }
1555              
1556 370 100       606 if ( wantarray ) {
1557 7         63 return @ret;
1558             }
1559             else { # in scalar context
1560 363 100       1408 return defined $ret[0] ? $ret[0] : undef;
1561             }
1562             }
1563             }
1564              
1565              
1566             sub _incr_parse {
1567 393     393   685 my ($self, $coder) = @_;
1568 393         996 my $text = $self->{incr_text};
1569 393         699 my $len = length $text;
1570 393         532 my $p = $self->{incr_pos};
1571              
1572             INCR_PARSE:
1573 393         800 while ( $len > $p ) {
1574 3084         4463 my $s = substr( $text, $p, 1 );
1575 3084 50       4910 last INCR_PARSE unless defined $s;
1576 3084         3871 my $mode = $self->{incr_mode};
1577              
1578 3084 100 100     11661 if ( $mode == INCR_M_WS ) {
    50          
    100          
    100          
    100          
    100          
    50          
1579 335         639 while ( $len > $p ) {
1580 594         1210 $s = substr( $text, $p, 1 );
1581 594 50       940 last INCR_PARSE unless defined $s;
1582 594 100       1073 if ( ord($s) > ord " " ) {
1583 328 100       609 if ( $s eq '#' ) {
1584 6         16 $self->{incr_mode} = INCR_M_C0;
1585 6         13 redo INCR_PARSE;
1586             } else {
1587 322         427 $self->{incr_mode} = INCR_M_JSON;
1588 322         607 redo INCR_PARSE;
1589             }
1590             }
1591 266         496 $p++;
1592             }
1593             } elsif ( $mode == INCR_M_BS ) {
1594 0         0 $p++;
1595 0         0 $self->{incr_mode} = INCR_M_STR;
1596 0         0 redo INCR_PARSE;
1597             } elsif ( $mode == INCR_M_C0 or $mode == INCR_M_C1 ) {
1598 9         18 while ( $len > $p ) {
1599 45         52 $s = substr( $text, $p, 1 );
1600 45 50       75 last INCR_PARSE unless defined $s;
1601 45 100       68 if ( $s eq "\n" ) {
1602 9 100       17 $self->{incr_mode} = $self->{incr_mode} == INCR_M_C0 ? INCR_M_WS : INCR_M_JSON;
1603 9         13 last;
1604             }
1605 36         57 $p++;
1606             }
1607 9         16 next;
1608             } elsif ( $mode == INCR_M_TFN ) {
1609 36 50 66     74 last INCR_PARSE if $p >= $len && $self->{incr_nest};
1610 35         62 while ( $len > $p ) {
1611 140         211 $s = substr( $text, $p++, 1 );
1612 140 100 66     489 next if defined $s and $s =~ /[rueals]/;
1613 35         47 last;
1614             }
1615 35         43 $p--;
1616 35         48 $self->{incr_mode} = INCR_M_JSON;
1617              
1618 35 50       62 last INCR_PARSE unless $self->{incr_nest};
1619 35         52 redo INCR_PARSE;
1620             } elsif ( $mode == INCR_M_NUM ) {
1621 399 100 100     745 last INCR_PARSE if $p >= $len && $self->{incr_nest};
1622 396         774 while ( $len > $p ) {
1623 482         682 $s = substr( $text, $p++, 1 );
1624 482 100 66     1561 next if defined $s and $s =~ /[0-9eE.+\-]/;
1625 389         505 last;
1626             }
1627 396         473 $p--;
1628 396         528 $self->{incr_mode} = INCR_M_JSON;
1629              
1630 396 100       641 last INCR_PARSE unless $self->{incr_nest};
1631 378         580 redo INCR_PARSE;
1632             } elsif ( $mode == INCR_M_STR ) {
1633 805         1386 while ( $len > $p ) {
1634 84413         104351 $s = substr( $text, $p, 1 );
1635 84413 50       124809 last INCR_PARSE unless defined $s;
1636 84413 100       146410 if ( $s eq '"' ) {
    100          
1637 780         920 $p++;
1638 780         1053 $self->{incr_mode} = INCR_M_JSON;
1639              
1640 780 100       1320 last INCR_PARSE unless $self->{incr_nest};
1641 760         1093 redo INCR_PARSE;
1642             }
1643             elsif ( $s eq '\\' ) {
1644 508         572 $p++;
1645 508 50       931 if ( !defined substr($text, $p, 1) ) {
1646 0         0 $self->{incr_mode} = INCR_M_BS;
1647 0         0 last INCR_PARSE;
1648             }
1649             }
1650 83633         124952 $p++;
1651             }
1652             } elsif ( $mode == INCR_M_JSON ) {
1653 1500         2537 while ( $len > $p ) {
1654 3614         5410 $s = substr( $text, $p++, 1 );
1655 3614 50 66     20917 if ( $s eq "\x00" ) {
    100 100        
    100 100        
    100 100        
    100          
    100          
    100          
    100          
1656 0         0 $p--;
1657 0         0 last INCR_PARSE;
1658             } elsif ( $s =~ /^[\t\n\r ]$/) {
1659 724 50       1330 if ( !$self->{incr_nest} ) {
1660 0         0 $p--; # do not eat the whitespace, let the next round do it
1661 0         0 last INCR_PARSE;
1662             }
1663 724         1230 next;
1664             } elsif ( $s eq 't' or $s eq 'f' or $s eq 'n' ) {
1665 36         63 $self->{incr_mode} = INCR_M_TFN;
1666 36         51 redo INCR_PARSE;
1667             } elsif ( $s =~ /^[0-9\-]$/ ) {
1668 398         615 $self->{incr_mode} = INCR_M_NUM;
1669 398         606 redo INCR_PARSE;
1670             } elsif ( $s eq '"' ) {
1671 783         1134 $self->{incr_mode} = INCR_M_STR;
1672 783         1115 redo INCR_PARSE;
1673             } elsif ( $s eq '[' or $s eq '{' ) {
1674 383 100       890 if ( ++$self->{incr_nest} > $coder->get_max_depth ) {
1675 1         101 Carp::croak('json text or perl structure exceeds maximum nesting level (max_depth set too low?)');
1676             }
1677 382         733 next;
1678             } elsif ( $s eq ']' or $s eq '}' ) {
1679 369 100       769 if ( --$self->{incr_nest} <= 0 ) {
1680 270         423 last INCR_PARSE;
1681             }
1682             } elsif ( $s eq '#' ) {
1683 3         6 $self->{incr_mode} = INCR_M_C1;
1684 3         4 redo INCR_PARSE;
1685             }
1686             }
1687             }
1688             }
1689              
1690 392         542 $self->{incr_pos} = $p;
1691 392 100       936 $self->{incr_parsing} = $p ? 1 : 0; # for backward compatibility
1692             }
1693              
1694              
1695             sub incr_text {
1696 0 0   0   0 if ( $_[0]->{incr_pos} ) {
1697 0         0 Carp::croak("incr_text cannot be called when the incremental parser already started parsing");
1698             }
1699 0         0 $_[0]->{incr_text};
1700             }
1701              
1702              
1703             sub incr_skip {
1704 2     2   4 my $self = shift;
1705 2         7 $self->{incr_text} = substr( $self->{incr_text}, $self->{incr_pos} );
1706 2         4 $self->{incr_pos} = 0;
1707 2         16 $self->{incr_mode} = 0;
1708 2         6 $self->{incr_nest} = 0;
1709             }
1710              
1711              
1712             sub incr_reset {
1713 0     0     my $self = shift;
1714 0           $self->{incr_text} = undef;
1715 0           $self->{incr_pos} = 0;
1716 0           $self->{incr_mode} = 0;
1717 0           $self->{incr_nest} = 0;
1718             }
1719              
1720             ###############################
1721              
1722              
1723             1;
1724             __END__