File Coverage

blib/lib/FlashVideo/JSON.pm
Criterion Covered Total %
statement 30 30 100.0
branch 26 28 92.8
condition 6 6 100.0
subroutine 3 3 100.0
pod 0 1 0.0
total 65 68 95.5


line stmt bran cond sub pod time code
1             package FlashVideo::JSON;
2             # Very simple JSON parser, loosely based on
3             # http://code.google.com/p/json-sans-eval
4             # Public domain.
5              
6 1     1   22581 use strict;
  1         2  
  1         58  
7 1     1   6 use base 'Exporter';
  1         3  
  1         741  
8             our @EXPORT = qw(from_json);
9              
10             my $number = qr{(?:-?\b(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b)};
11             my $oneChar = qr{(?:[^\0-\x08\x0a-\x1f\"\\]|\\(?:["/\\bfnrt]|u[0-9A-Fa-f]{4}))};
12             my $string = qr{(?:"$oneChar*")};
13             my $jsonToken = qr{(?:false|true|null|[\{\}\[\]]|$number|$string)};
14             my $escapeSequence = qr{\\(?:([^u])|u(.{4}))};
15              
16             my %escapes = (
17             '\\' => '\\',
18             '"' => '"',
19             '/' => '/',
20             'b' => "\b",
21             'f' => "\f",
22             'n' => "\xA",
23             'r' => "\xD",
24             't' => "\t"
25             );
26              
27             sub from_json {
28 8     8 0 24 my($in) = @_;
29              
30 8         84 my @tokens = $in =~ /$jsonToken/go;
31 8 100       23 my $result = $tokens[0] eq '{' ? {} : [];
32             # Handle something other than array/object at toplevel
33 8 100       25 shift @tokens if $tokens[0] =~ /^[\[\{]/;
34              
35 8         8 my $key; # key to use for next value
36 8         13 my @stack = $result;
37 8         13 for my $t(@tokens) {
38 27         36 my $ft = substr $t, 0, 1;
39 27         26 my $cont = $stack[0];
40              
41 27 100 100     122 if($ft eq '"') {
    100 100        
    100          
42 9         16 my $s = substr $t, 1, length($t) - 2;
43 9 50       21 $s =~ s/$escapeSequence/$1 ? $escapes{$1} : chr hex $2/geo;
  5         24  
44 9 100       14 if(!defined $key) {
45 7 100       13 if(ref $cont eq 'ARRAY') {
46 2         6 $cont->[@$cont] = $s;
47             } else {
48 5         5 $key = $s;
49 5         9 next; # need to save $key
50             }
51             } else {
52 2         6 $cont->{$key} = $s;
53             }
54             } elsif($ft eq '[' || $ft eq '{') {
55 2 50       11 unshift @stack,
    100          
56             (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) = $ft eq '[' ? [] : {};
57             } elsif($ft eq ']' || $ft eq '}') {
58 5         7 shift @stack;
59             } else {
60 11 100       84 (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) =
    100          
    100          
    100          
61             $ft eq 'f' ? 0 # false
62             : $ft eq 'n' ? undef # null
63             : $ft eq 't' ? 1 # true
64             : $t; # sign or digit
65             }
66 22         40 undef $key;
67             }
68              
69 8         52 return $result;
70             }
71              
72             1;