| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Data::MessagePack::PP; | 
| 2 | 25 |  |  | 25 |  | 365 | use 5.008001; | 
|  | 25 |  |  |  |  | 74 |  | 
| 3 | 25 |  |  | 25 |  | 110 | use strict; | 
|  | 25 |  |  |  |  | 49 |  | 
|  | 25 |  |  |  |  | 897 |  | 
| 4 | 25 |  |  | 25 |  | 127 | use warnings; | 
|  | 25 |  |  |  |  | 72 |  | 
|  | 25 |  |  |  |  | 700 |  | 
| 5 | 25 |  |  | 25 |  | 119 | no warnings 'recursion'; | 
|  | 25 |  |  |  |  | 48 |  | 
|  | 25 |  |  |  |  | 705 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 25 |  |  | 25 |  | 166 | use Carp (); | 
|  | 25 |  |  |  |  | 58 |  | 
|  | 25 |  |  |  |  | 464 |  | 
| 8 | 25 |  |  | 25 |  | 110 | use B (); | 
|  | 25 |  |  |  |  | 50 |  | 
|  | 25 |  |  |  |  | 542 |  | 
| 9 | 25 |  |  | 25 |  | 112 | use Config; | 
|  | 25 |  |  |  |  | 53 |  | 
|  | 25 |  |  |  |  | 13828 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | # See also | 
| 12 |  |  |  |  |  |  | # http://redmine.msgpack.org/projects/msgpack/wiki/FormatSpec | 
| 13 |  |  |  |  |  |  | # http://cpansearch.perl.org/src/YAPPO/Data-Model-0.00006/lib/Data/Model/Driver/Memcached.pm | 
| 14 |  |  |  |  |  |  | # http://frox25.no-ip.org/~mtve/wiki/MessagePack.html : reference to using CORE::pack, CORE::unpack | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | BEGIN { | 
| 17 | 25 |  |  | 25 |  | 90 | my $unpack_int64_slow; | 
| 18 |  |  |  |  |  |  | my $unpack_uint64_slow; | 
| 19 |  |  |  |  |  |  |  | 
| 20 | 25 | 50 |  |  |  | 46 | if(!eval { pack 'Q', 1 }) { # don't have quad types | 
|  | 25 |  |  |  |  | 82 |  | 
| 21 |  |  |  |  |  |  | # emulates quad types with Math::BigInt. | 
| 22 |  |  |  |  |  |  | # very slow but works well. | 
| 23 |  |  |  |  |  |  | $unpack_int64_slow = sub { | 
| 24 | 0 |  |  |  |  | 0 | require Math::BigInt; | 
| 25 | 0 |  |  |  |  | 0 | my $high = unpack_uint32( $_[0], $_[1] ); | 
| 26 | 0 |  |  |  |  | 0 | my $low  = unpack_uint32( $_[0], $_[1] + 4); | 
| 27 |  |  |  |  |  |  |  | 
| 28 | 0 | 0 |  |  |  | 0 | if($high < 0xF0000000) { # positive | 
| 29 | 0 |  |  |  |  | 0 | $high = Math::BigInt->new( $high ); | 
| 30 | 0 |  |  |  |  | 0 | $low  = Math::BigInt->new( $low  ); | 
| 31 | 0 |  |  |  |  | 0 | return +($high << 32 | $low)->bstr; | 
| 32 |  |  |  |  |  |  | } | 
| 33 |  |  |  |  |  |  | else { # negative | 
| 34 | 0 |  |  |  |  | 0 | $high = Math::BigInt->new( ~$high ); | 
| 35 | 0 |  |  |  |  | 0 | $low  = Math::BigInt->new( ~$low  ); | 
| 36 | 0 |  |  |  |  | 0 | return +( -($high << 32 | $low + 1) )->bstr; | 
| 37 |  |  |  |  |  |  | } | 
| 38 | 0 |  |  |  |  | 0 | }; | 
| 39 |  |  |  |  |  |  | $unpack_uint64_slow = sub { | 
| 40 | 0 |  |  |  |  | 0 | require Math::BigInt; | 
| 41 | 0 |  |  |  |  | 0 | my $high = Math::BigInt->new( unpack_uint32( $_[0], $_[1]) ); | 
| 42 | 0 |  |  |  |  | 0 | my $low  = Math::BigInt->new( unpack_uint32( $_[0], $_[1] + 4) ); | 
| 43 | 0 |  |  |  |  | 0 | return +($high << 32 | $low)->bstr; | 
| 44 | 0 |  |  |  |  | 0 | }; | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  |  | 
| 47 | 25 |  |  | 36 |  | 120 | *unpack_uint16 = sub { return unpack 'n', substr( $_[0], $_[1], 2 ) }; | 
|  | 36 |  |  |  |  | 135 |  | 
| 48 | 25 |  |  | 46 |  | 81 | *unpack_uint32 = sub { return unpack 'N', substr( $_[0], $_[1], 4 ) }; | 
|  | 46 |  |  |  |  | 153 |  | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | # For ARM OABI | 
| 51 | 25 |  |  |  |  | 203 | my $bo_is_me = unpack ( 'd', "\x00\x00\xf0\x3f\x00\x00\x00\x00") == 1; | 
| 52 | 25 |  |  |  |  | 43 | my $pack_double_oabi; | 
| 53 |  |  |  |  |  |  | my $unpack_double_oabi; | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # for pack and unpack compatibility | 
| 56 | 25 | 50 |  |  |  | 73 | if ( $] < 5.010 ) { | 
| 57 | 0 |  |  |  |  | 0 | my $bo_is_le = ( $Config{byteorder} =~ /^1234/ ); | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 0 | 0 |  |  |  | 0 | if ($bo_is_me) { | 
| 60 |  |  |  |  |  |  | $pack_double_oabi = sub { | 
| 61 | 0 |  |  |  |  | 0 | my @v = unpack( 'V2', pack( 'd', $_[0] ) ); | 
| 62 | 0 |  |  |  |  | 0 | return pack 'CN2', 0xcb, @v[0,1]; | 
| 63 | 0 |  |  |  |  | 0 | }; | 
| 64 |  |  |  |  |  |  | $unpack_double_oabi = sub { | 
| 65 | 0 |  |  |  |  | 0 | my @v = unpack( 'V2', substr( $_[0], $_[1], 8 ) ); | 
| 66 | 0 |  |  |  |  | 0 | return unpack( 'd', pack( 'N2', @v[0,1] ) ); | 
| 67 | 0 |  |  |  |  | 0 | }; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | *unpack_int16  = sub { | 
| 71 | 0 |  |  |  |  | 0 | my $v = unpack 'n', substr( $_[0], $_[1], 2 ); | 
| 72 | 0 | 0 |  |  |  | 0 | return $v ? $v - 0x10000 : 0; | 
| 73 | 0 |  |  |  |  | 0 | }; | 
| 74 |  |  |  |  |  |  | *unpack_int32  = sub { | 
| 75 | 25 |  |  | 25 |  | 167 | no warnings; # avoid for warning about Hexadecimal number | 
|  | 25 |  |  |  |  | 61 |  | 
|  | 25 |  |  |  |  | 21172 |  | 
| 76 | 0 |  |  |  |  | 0 | my $v = unpack 'N', substr( $_[0], $_[1], 4 ); | 
| 77 | 0 | 0 |  |  |  | 0 | return $v ? $v - 0x100000000 : 0; | 
| 78 | 0 |  |  |  |  | 0 | }; | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | # In reality, since 5.9.2 '>' is introduced. but 'n!' and 'N!'? | 
| 81 | 0 | 0 |  |  |  | 0 | if($bo_is_le) { | 
| 82 |  |  |  |  |  |  | *pack_uint64 = sub { | 
| 83 | 0 |  |  |  |  | 0 | my @v = unpack( 'V2', pack( 'Q', $_[0] ) ); | 
| 84 | 0 |  |  |  |  | 0 | return pack 'CN2', 0xcf, @v[1,0]; | 
| 85 | 0 |  |  |  |  | 0 | }; | 
| 86 |  |  |  |  |  |  | *pack_int64 = sub { | 
| 87 | 0 |  |  |  |  | 0 | my @v = unpack( 'V2', pack( 'q', $_[0] ) ); | 
| 88 | 0 |  |  |  |  | 0 | return pack 'CN2', 0xd3, @v[1,0]; | 
| 89 | 0 |  |  |  |  | 0 | }; | 
| 90 |  |  |  |  |  |  | *pack_double = $pack_double_oabi || sub { | 
| 91 |  |  |  |  |  |  | my @v = unpack( 'V2', pack( 'd', $_[0] ) ); | 
| 92 |  |  |  |  |  |  | return pack 'CN2', 0xcb, @v[1,0]; | 
| 93 | 0 |  | 0 |  |  | 0 | }; | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | *unpack_float = sub { | 
| 96 | 0 |  |  |  |  | 0 | my @v = unpack( 'v2', substr( $_[0], $_[1], 4 ) ); | 
| 97 | 0 |  |  |  |  | 0 | return unpack( 'f', pack( 'n2', @v[1,0] ) ); | 
| 98 | 0 |  |  |  |  | 0 | }; | 
| 99 |  |  |  |  |  |  | *unpack_double = $unpack_double_oabi || sub { | 
| 100 |  |  |  |  |  |  | my @v = unpack( 'V2', substr( $_[0], $_[1], 8 ) ); | 
| 101 |  |  |  |  |  |  | return unpack( 'd', pack( 'N2', @v[1,0] ) ); | 
| 102 | 0 |  | 0 |  |  | 0 | }; | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | *unpack_int64 = $unpack_int64_slow || sub { | 
| 105 |  |  |  |  |  |  | my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) ); | 
| 106 |  |  |  |  |  |  | return unpack( 'q', pack( 'N2', @v[1,0] ) ); | 
| 107 | 0 |  | 0 |  |  | 0 | }; | 
| 108 |  |  |  |  |  |  | *unpack_uint64 = $unpack_uint64_slow || sub { | 
| 109 |  |  |  |  |  |  | my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) ); | 
| 110 |  |  |  |  |  |  | return unpack( 'Q', pack( 'N2', @v[1,0] ) ); | 
| 111 | 0 |  | 0 |  |  | 0 | }; | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  | else { # big endian | 
| 114 | 0 |  |  |  |  | 0 | *pack_uint64   = sub { return pack 'CQ', 0xcf, $_[0]; }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 115 | 0 |  |  |  |  | 0 | *pack_int64    = sub { return pack 'Cq', 0xd3, $_[0]; }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 116 | 0 |  | 0 |  |  | 0 | *pack_double   = $pack_double_oabi || sub { return pack 'Cd', 0xcb, $_[0]; }; | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 0 |  |  |  |  | 0 | *unpack_float  = sub { return unpack( 'f', substr( $_[0], $_[1], 4 ) ); }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 119 | 0 |  | 0 |  |  | 0 | *unpack_double = $unpack_double_oabi || sub { return unpack( 'd', substr( $_[0], $_[1], 8 ) ); }; | 
| 120 | 0 |  | 0 |  |  | 0 | *unpack_int64  = $unpack_int64_slow  || sub { unpack 'q', substr( $_[0], $_[1], 8 ); }; | 
| 121 | 0 |  | 0 |  |  | 0 | *unpack_uint64 = $unpack_uint64_slow || sub { unpack 'Q', substr( $_[0], $_[1], 8 ); }; | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  | else { # 5.10.0 or later | 
| 125 | 25 | 50 |  |  |  | 87 | if ($bo_is_me) { | 
| 126 |  |  |  |  |  |  | $pack_double_oabi = sub { | 
| 127 | 0 |  |  |  |  | 0 | my @v = unpack('V2' , pack('d', $_[0])); | 
| 128 | 0 |  |  |  |  | 0 | my $d = unpack('d', pack('V2', @v[1,0])); | 
| 129 | 0 |  |  |  |  | 0 | return pack 'Cd>', 0xcb, $d; | 
| 130 | 0 |  |  |  |  | 0 | }; | 
| 131 |  |  |  |  |  |  | $unpack_double_oabi = sub { | 
| 132 | 0 |  |  |  |  | 0 | my $first_word  = substr($_[0], $_[1], 4); | 
| 133 | 0 |  |  |  |  | 0 | my $second_word = substr($_[0], $_[1] + 4, 4); | 
| 134 | 0 |  |  |  |  | 0 | my $d_bin = $second_word . $first_word; | 
| 135 | 0 |  |  |  |  | 0 | return unpack( 'd>', $d_bin ); | 
| 136 | 0 |  |  |  |  | 0 | }; | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | # pack_int64/uint64 are used only when the perl support quad types | 
| 140 | 25 |  |  | 0 |  | 93 | *pack_uint64   = sub { return pack 'CQ>', 0xcf, $_[0]; }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 141 | 25 |  |  | 0 |  | 97 | *pack_int64    = sub { return pack 'Cq>', 0xd3, $_[0]; }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 142 | 25 |  | 50 | 27 |  | 181 | *pack_double   = $pack_double_oabi || sub { return pack 'Cd>', 0xcb, $_[0]; }; | 
|  | 27 |  |  |  |  | 138 |  | 
| 143 |  |  |  |  |  |  |  | 
| 144 | 25 |  |  | 4 |  | 91 | *unpack_float  = sub { return unpack( 'f>', substr( $_[0], $_[1], 4 ) ); }; | 
|  | 4 |  |  |  |  | 15 |  | 
| 145 | 25 |  | 50 | 112 |  | 158 | *unpack_double = $unpack_double_oabi || sub { return unpack( 'd>', substr( $_[0], $_[1], 8 ) ); }; | 
|  | 112 |  |  |  |  | 353 |  | 
| 146 | 25 |  |  | 34 |  | 448 | *unpack_int16  = sub { return unpack( 'n!', substr( $_[0], $_[1], 2 ) ); }; | 
|  | 34 |  |  |  |  | 150 |  | 
| 147 | 25 |  |  | 38 |  | 138 | *unpack_int32  = sub { return unpack( 'N!', substr( $_[0], $_[1], 4 ) ); }; | 
|  | 38 |  |  |  |  | 128 |  | 
| 148 |  |  |  |  |  |  |  | 
| 149 | 25 |  | 50 | 21 |  | 136 | *unpack_int64  = $unpack_int64_slow  || sub { return unpack( 'q>', substr( $_[0], $_[1], 8 ) ); }; | 
|  | 21 |  |  |  |  | 72 |  | 
| 150 | 25 |  | 50 | 8 |  | 223 | *unpack_uint64 = $unpack_uint64_slow || sub { return unpack( 'Q>', substr( $_[0], $_[1], 8 ) ); }; | 
|  | 8 |  |  |  |  | 31 |  | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | # fixin package symbols | 
| 154 | 25 |  |  | 25 |  | 168 | no warnings 'once'; | 
|  | 25 |  |  |  |  | 44 |  | 
|  | 25 |  |  |  |  | 2234 |  | 
| 155 | 25 |  |  |  |  | 462 | @Data::MessagePack::ISA           = qw(Data::MessagePack::PP); | 
| 156 | 25 |  |  |  |  | 390 | @Data::MessagePack::Unpacker::ISA = qw(Data::MessagePack::PP::Unpacker); | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 25 |  |  |  |  | 144 | *true  = \&Data::MessagePack::true; | 
| 159 | 25 |  |  |  |  | 37147 | *false = \&Data::MessagePack::false; | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | sub _unexpected { | 
| 163 | 0 |  |  | 0 |  | 0 | Carp::confess("Unexpected " . sprintf(shift, @_) . " found"); | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | # | 
| 168 |  |  |  |  |  |  | # PACK | 
| 169 |  |  |  |  |  |  | # | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | our $_max_depth; | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub pack :method { | 
| 174 | 277 |  |  | 277 | 0 | 173625 | my($self, $data, $max_depth) = @_; | 
| 175 | 277 | 50 |  |  |  | 645 | Carp::croak('Usage: Data::MessagePack->pack($dat [,$max_depth])') if @_ < 2; | 
| 176 | 277 | 100 |  |  |  | 519 | $_max_depth = defined $max_depth ? $max_depth : 512; # init | 
| 177 |  |  |  |  |  |  |  | 
| 178 | 277 | 100 |  |  |  | 494 | if(not ref $self) { | 
| 179 | 233 |  | 100 |  |  | 1071 | $self = $self->new( | 
|  |  |  | 50 |  |  |  |  | 
| 180 |  |  |  |  |  |  | prefer_integer => $Data::MessagePack::PreferInteger || 0, | 
| 181 |  |  |  |  |  |  | canonical      => $Data::MessagePack::Canonical     || 0, | 
| 182 |  |  |  |  |  |  | ); | 
| 183 |  |  |  |  |  |  | } | 
| 184 | 277 |  |  |  |  | 602 | return $self->_pack( $data ); | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | sub _pack { | 
| 189 | 5736 |  |  | 5736 |  | 7606 | my ( $self, $value ) = @_; | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 5736 |  |  |  |  | 6581 | local $_max_depth = $_max_depth - 1; | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 5736 | 100 |  |  |  | 7999 | if ( $_max_depth < 0 ) { | 
| 194 | 4 |  |  |  |  | 7336 | Carp::croak("perl structure exceeds maximum nesting level (max_depth set too low?)"); | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 | 5732 | 100 |  |  |  | 8835 | return CORE::pack( 'C', 0xc0 ) if ( not defined $value ); | 
| 198 |  |  |  |  |  |  |  | 
| 199 | 4934 | 100 |  |  |  | 8837 | if ( ref($value) eq 'ARRAY' ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 200 | 1156 |  |  |  |  | 1427 | my $num = @$value; | 
| 201 | 1156 | 0 |  |  |  | 2199 | my $header = | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | $num < 16          ? CORE::pack( 'C',  0x90 + $num ) | 
| 203 |  |  |  |  |  |  | : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xdc,  $num ) | 
| 204 |  |  |  |  |  |  | : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xdd,  $num ) | 
| 205 |  |  |  |  |  |  | : _unexpected("number %d", $num) | 
| 206 |  |  |  |  |  |  | ; | 
| 207 | 1156 |  |  |  |  | 1949 | return join( '', $header, map { $self->_pack( $_ ) } @$value ); | 
|  | 3868 |  |  |  |  | 9024 |  | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | elsif ( ref($value) eq 'HASH' ) { | 
| 211 | 754 |  |  |  |  | 1294 | my $num = keys %$value; | 
| 212 | 754 | 0 |  |  |  | 1440 | my $header = | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | $num < 16          ? CORE::pack( 'C',  0x80 + $num ) | 
| 214 |  |  |  |  |  |  | : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xde,  $num ) | 
| 215 |  |  |  |  |  |  | : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xdf,  $num ) | 
| 216 |  |  |  |  |  |  | : _unexpected("number %d", $num) | 
| 217 |  |  |  |  |  |  | ; | 
| 218 |  |  |  |  |  |  |  | 
| 219 | 754 | 100 |  |  |  | 1069 | if ($self->{canonical}) { | 
| 220 | 11 |  |  |  |  | 33 | return join( '', $header, map { $self->_pack( $_ ), $self->_pack($value->{$_}) } sort { $a cmp $b } keys %$value ); | 
|  | 42 |  |  |  |  | 77 |  | 
|  | 69 |  |  |  |  | 79 |  | 
| 221 |  |  |  |  |  |  | } else { | 
| 222 | 743 |  |  |  |  | 1164 | return join( '', $header, map { $self->_pack( $_ ) } %$value ); | 
|  | 1490 |  |  |  |  | 2169 |  | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  | } | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | elsif ( ref( $value ) eq 'Data::MessagePack::Boolean' ) { | 
| 227 | 62 | 100 |  |  |  | 71 | return  CORE::pack( 'C', ${$value} ? 0xc3 : 0xc2 ); | 
|  | 62 |  |  |  |  | 376 |  | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  |  | 
| 231 | 2962 |  |  |  |  | 5842 | my $b_obj = B::svref_2object( \$value ); | 
| 232 | 2962 |  |  |  |  | 4612 | my $flags = $b_obj->FLAGS; | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 2962 | 100 |  |  |  | 5180 | if ( $flags & B::SVp_POK ) { # raw / check needs before double | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 235 |  |  |  |  |  |  |  | 
| 236 | 1669 | 100 |  |  |  | 2496 | if ( $self->{prefer_integer} ) { | 
| 237 | 35 | 100 |  |  |  | 147 | if ( $value =~ /^-?[0-9]+$/ ) { # ok? | 
| 238 |  |  |  |  |  |  | # checks whether $value is in (u)int32 | 
| 239 | 23 |  |  |  |  | 46 | my $ivalue = 0 + $value; | 
| 240 | 23 | 100 | 100 |  |  | 153 | if (!( | 
|  |  |  | 66 |  |  |  |  | 
| 241 |  |  |  |  |  |  | $ivalue > 0xFFFFFFFF | 
| 242 |  |  |  |  |  |  | or $ivalue < ('-' . 0x80000000) # for XS compat | 
| 243 |  |  |  |  |  |  | or $ivalue != B::svref_2object(\$ivalue)->int_value | 
| 244 |  |  |  |  |  |  | )) { | 
| 245 | 17 |  |  |  |  | 43 | return $self->_pack( $ivalue ); | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  | # fallthrough | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  | # fallthrough | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 1652 | 100 |  |  |  | 2619 | utf8::encode( $value ) if utf8::is_utf8( $value ); | 
| 253 |  |  |  |  |  |  |  | 
| 254 | 1652 |  |  |  |  | 1785 | my $num = length $value; | 
| 255 | 1652 |  |  |  |  | 1699 | my $header; | 
| 256 | 1652 | 100 |  |  |  | 2091 | if ($self->{utf8}) { # Str | 
| 257 | 26 | 0 |  |  |  | 94 | $header = | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | $num < 32          ? CORE::pack( 'C',  0xa0 + $num ) | 
| 259 |  |  |  |  |  |  | : $num < 2 ** 8  - 1 ? CORE::pack( 'CC', 0xd9, $num) | 
| 260 |  |  |  |  |  |  | : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xda, $num ) | 
| 261 |  |  |  |  |  |  | : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xdb, $num ) | 
| 262 |  |  |  |  |  |  | : _unexpected('number %d', $num); | 
| 263 |  |  |  |  |  |  | } else { # Bin | 
| 264 | 1626 | 50 |  |  |  | 2952 | $header = | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 265 |  |  |  |  |  |  | $num < 2 ** 8 - 1 ? CORE::pack( 'CC',  0xc4, $num) | 
| 266 |  |  |  |  |  |  | : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xc5, $num ) | 
| 267 |  |  |  |  |  |  | : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xc6, $num ) | 
| 268 |  |  |  |  |  |  | : _unexpected('number %d', $num); | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 1652 |  |  |  |  | 4835 | return $header . $value; | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  | elsif( $flags & B::SVp_NOK ) { # double only | 
| 275 | 27 |  |  |  |  | 52 | return pack_double( $value ); | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  | elsif ( $flags & B::SVp_IOK ) { | 
| 278 | 1266 | 100 |  |  |  | 1837 | if ($value >= 0) { # UV | 
| 279 | 1197 | 50 |  |  |  | 4086 | return    $value <= 127 ?    CORE::pack 'C',        $value | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | : $value < 2 **  8 ? CORE::pack 'CC', 0xcc, $value | 
| 281 |  |  |  |  |  |  | : $value < 2 ** 16 ? CORE::pack 'Cn', 0xcd, $value | 
| 282 |  |  |  |  |  |  | : $value < 2 ** 32 ? CORE::pack 'CN', 0xce, $value | 
| 283 |  |  |  |  |  |  | : pack_uint64( $value ); | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  | else { # IV | 
| 286 | 69 | 50 |  |  |  | 318 | return    -$value <= 32 ?      CORE::pack 'C', ($value & 255) | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | : -$value <= 2 **  7 ? CORE::pack 'Cc', 0xd0, $value | 
| 288 |  |  |  |  |  |  | : -$value <= 2 ** 15 ? CORE::pack 'Cn', 0xd1, $value | 
| 289 |  |  |  |  |  |  | : -$value <= 2 ** 31 ? CORE::pack 'CN', 0xd2, $value | 
| 290 |  |  |  |  |  |  | : pack_int64( $value ); | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  | else { | 
| 294 | 0 |  |  |  |  | 0 | _unexpected("data type %s", $b_obj); | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | # | 
| 300 |  |  |  |  |  |  | # UNPACK | 
| 301 |  |  |  |  |  |  | # | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | our $_utf8 = 0; | 
| 304 |  |  |  |  |  |  | my $p; # position variables for speed. | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | sub _insufficient { | 
| 307 | 0 |  |  | 0 |  | 0 | Carp::confess("Insufficient bytes (pos=$p, type=@_)"); | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | sub unpack :method { | 
| 311 | 395 |  |  | 395 | 0 | 2413 | $p = 0; # init | 
| 312 | 395 |  | 100 |  |  | 1360 | $_utf8 = (ref($_[0]) && $_[0]->{utf8}) || $_utf8; | 
| 313 | 395 |  |  |  |  | 762 | my $data = _unpack( $_[1] ); | 
| 314 | 395 | 100 |  |  |  | 916 | if($p < length($_[1])) { | 
| 315 | 44 |  |  |  |  | 3702 | Carp::croak("Data::MessagePack->unpack: extra bytes"); | 
| 316 |  |  |  |  |  |  | } | 
| 317 | 351 |  |  |  |  | 1278 | return $data; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | my $T_STR             = 0x01; | 
| 321 |  |  |  |  |  |  | my $T_ARRAY           = 0x02; | 
| 322 |  |  |  |  |  |  | my $T_MAP             = 0x04; | 
| 323 |  |  |  |  |  |  | my $T_BIN             = 0x08; | 
| 324 |  |  |  |  |  |  | my $T_DIRECT          = 0x10; # direct mapping (e.g. 0xc0 <-> nil) | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | my @typemap = ( (0x00) x 256 ); | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | $typemap[$_] |= $T_ARRAY for | 
| 329 |  |  |  |  |  |  | 0x90 .. 0x9f, # fix array | 
| 330 |  |  |  |  |  |  | 0xdc,         # array16 | 
| 331 |  |  |  |  |  |  | 0xdd,         # array32 | 
| 332 |  |  |  |  |  |  | ; | 
| 333 |  |  |  |  |  |  | $typemap[$_] |= $T_MAP for | 
| 334 |  |  |  |  |  |  | 0x80 .. 0x8f, # fix map | 
| 335 |  |  |  |  |  |  | 0xde,         # map16 | 
| 336 |  |  |  |  |  |  | 0xdf,         # map32 | 
| 337 |  |  |  |  |  |  | ; | 
| 338 |  |  |  |  |  |  | $typemap[$_] |= $T_STR for | 
| 339 |  |  |  |  |  |  | 0xa0 .. 0xbf, # fix str | 
| 340 |  |  |  |  |  |  | 0xd9,         # str8 | 
| 341 |  |  |  |  |  |  | 0xda,         # str16 | 
| 342 |  |  |  |  |  |  | 0xdb,         # str32 | 
| 343 |  |  |  |  |  |  | ; | 
| 344 |  |  |  |  |  |  | $typemap[$_] |= $T_BIN for | 
| 345 |  |  |  |  |  |  | 0xc4,         # bin 8 | 
| 346 |  |  |  |  |  |  | 0xc5,         # bin 16 | 
| 347 |  |  |  |  |  |  | 0xc6,         # bin 32 | 
| 348 |  |  |  |  |  |  | ; | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  | my @byte2value; | 
| 351 |  |  |  |  |  |  | foreach my $pair( | 
| 352 |  |  |  |  |  |  | [0xc3, true], | 
| 353 |  |  |  |  |  |  | [0xc2, false], | 
| 354 |  |  |  |  |  |  | [0xc0, undef], | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | (map { [ $_, $_ ] }         0x00 .. 0x7f), # positive fixnum | 
| 357 |  |  |  |  |  |  | (map { [ $_, $_ - 0x100 ] } 0xe0 .. 0xff), # negative fixnum | 
| 358 |  |  |  |  |  |  | ) { | 
| 359 |  |  |  |  |  |  | $typemap[    $pair->[0] ] |= $T_DIRECT; | 
| 360 |  |  |  |  |  |  | $byte2value[ $pair->[0] ]  = $pair->[1]; | 
| 361 |  |  |  |  |  |  | } | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | sub _fetch_size { | 
| 364 | 3151 |  |  | 3151 |  | 4362 | my($value_ref, $byte, $x8, $x16, $x32, $x_fixbits) = @_; | 
| 365 | 3151 | 100 | 100 |  |  | 6927 | if ( defined($x8) && $byte == $x8 ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 366 | 1793 |  |  |  |  | 1985 | $p += 1; | 
| 367 | 1793 | 50 |  |  |  | 1806 | $p <= length(${$value_ref}) or _insufficient('x/8'); | 
|  | 1793 |  |  |  |  | 2770 |  | 
| 368 | 1793 |  |  |  |  | 2038 | return unpack 'C', substr( ${$value_ref}, $p - 1, 1); | 
|  | 1793 |  |  |  |  | 3452 |  | 
| 369 |  |  |  |  |  |  | } | 
| 370 |  |  |  |  |  |  | elsif ( $byte == $x16 ) { | 
| 371 | 57 |  |  |  |  | 92 | $p += 2; | 
| 372 | 57 | 50 |  |  |  | 101 | $p <= length(${$value_ref}) or _insufficient('x/16'); | 
|  | 57 |  |  |  |  | 126 |  | 
| 373 | 57 |  |  |  |  | 82 | return unpack 'n', substr( ${$value_ref}, $p - 2, 2 ); | 
|  | 57 |  |  |  |  | 182 |  | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  | elsif ( $byte == $x32 ) { | 
| 376 | 36 |  |  |  |  | 46 | $p += 4; | 
| 377 | 36 | 50 |  |  |  | 42 | $p <= length(${$value_ref}) or _insufficient('x/32'); | 
|  | 36 |  |  |  |  | 68 |  | 
| 378 | 36 |  |  |  |  | 46 | return unpack 'N', substr( ${$value_ref}, $p - 4, 4 ); | 
|  | 36 |  |  |  |  | 83 |  | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  | else { # fix raw | 
| 381 | 1265 |  |  |  |  | 1944 | return $byte & ~$x_fixbits; | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | sub _unpack { | 
| 386 | 5438 |  |  | 5438 |  | 7313 | my ( $value ) = @_; | 
| 387 | 5438 | 50 |  |  |  | 7760 | $p < length($value) or _insufficient('header byte'); | 
| 388 |  |  |  |  |  |  | # get a header byte | 
| 389 | 5438 |  |  |  |  | 6662 | my $byte = ord( substr $value, $p, 1 ); | 
| 390 | 5438 |  |  |  |  | 5524 | $p++; | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | # +/- fixnum, nil, true, false | 
| 393 | 5438 | 100 |  |  |  | 9983 | return $byte2value[$byte] if $typemap[$byte] & $T_DIRECT; | 
| 394 |  |  |  |  |  |  |  | 
| 395 | 3531 | 100 |  |  |  | 7925 | if ( $typemap[$byte] & $T_STR ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 396 | 55 |  |  |  |  | 91 | my $size = _fetch_size(\$value, $byte, 0xd9, 0xda, 0xdb, 0xa0); | 
| 397 | 55 |  |  |  |  | 91 | my $s    = substr( $value, $p, $size ); | 
| 398 | 55 | 50 |  |  |  | 98 | length($s) == $size or _insufficient('raw'); | 
| 399 | 55 |  |  |  |  | 61 | $p      += $size; | 
| 400 | 55 |  |  |  |  | 115 | utf8::decode($s); | 
| 401 | 55 |  |  |  |  | 121 | return $s; | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  | elsif ( $typemap[$byte] & $T_ARRAY ) { | 
| 404 | 398 |  |  |  |  | 658 | my $size = _fetch_size(\$value, $byte, undef, 0xdc, 0xdd, 0x90); | 
| 405 | 398 |  |  |  |  | 500 | my @array; | 
| 406 | 398 |  |  |  |  | 967 | push @array, _unpack( $value ) while --$size >= 0; | 
| 407 | 398 |  |  |  |  | 844 | return \@array; | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  | elsif ( $typemap[$byte] & $T_MAP ) { | 
| 410 | 897 |  |  |  |  | 1259 | my $size = _fetch_size(\$value, $byte, undef, 0xde, 0xdf, 0x80); | 
| 411 | 897 |  |  |  |  | 1024 | my %map; | 
| 412 | 897 |  |  |  |  | 1377 | while(--$size >= 0) { | 
| 413 | 25 |  |  | 25 |  | 198 | no warnings; # for undef key case | 
|  | 25 |  |  |  |  | 62 |  | 
|  | 25 |  |  |  |  | 17990 |  | 
| 414 | 868 |  |  |  |  | 1144 | my $key = _unpack( $value ); | 
| 415 | 868 |  |  |  |  | 1172 | my $val = _unpack( $value ); | 
| 416 | 868 |  |  |  |  | 2482 | $map{ $key } = $val; | 
| 417 |  |  |  |  |  |  | } | 
| 418 | 897 |  |  |  |  | 2178 | return \%map; | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  | elsif ($typemap[$byte] & $T_BIN) { | 
| 421 | 1801 |  |  |  |  | 2473 | my $size = _fetch_size(\$value, $byte, 0xc4, 0xc5, 0xc6, 0x80); | 
| 422 | 1801 |  |  |  |  | 3141 | my $s    = substr( $value, $p, $size ); | 
| 423 | 1801 | 50 |  |  |  | 2713 | length($s) == $size or _insufficient('bin'); | 
| 424 | 1801 |  |  |  |  | 1913 | $p      += $size; | 
| 425 | 1801 | 100 |  |  |  | 2380 | utf8::decode($s) if $_utf8; | 
| 426 | 1801 |  |  |  |  | 2853 | return $s; | 
| 427 |  |  |  |  |  |  | } | 
| 428 |  |  |  |  |  |  | elsif ( $byte == 0xcc ) { # uint8 | 
| 429 | 35 |  |  |  |  | 54 | $p++; | 
| 430 | 35 | 50 |  |  |  | 85 | $p <= length($value) or _insufficient('uint8'); | 
| 431 | 35 |  |  |  |  | 114 | return CORE::unpack( 'C', substr( $value, $p - 1, 1 ) ); | 
| 432 |  |  |  |  |  |  | } | 
| 433 |  |  |  |  |  |  | elsif ( $byte == 0xcd ) { # uint16 | 
| 434 | 36 |  |  |  |  | 53 | $p += 2; | 
| 435 | 36 | 50 |  |  |  | 66 | $p <= length($value) or _insufficient('uint16'); | 
| 436 | 36 |  |  |  |  | 83 | return unpack_uint16( $value, $p - 2 ); | 
| 437 |  |  |  |  |  |  | } | 
| 438 |  |  |  |  |  |  | elsif ( $byte == 0xce ) { # unit32 | 
| 439 | 46 |  |  |  |  | 74 | $p += 4; | 
| 440 | 46 | 50 |  |  |  | 96 | $p <= length($value) or _insufficient('uint32'); | 
| 441 | 46 |  |  |  |  | 125 | return unpack_uint32( $value, $p - 4 ); | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  | elsif ( $byte == 0xcf ) { # unit64 | 
| 444 | 8 |  |  |  |  | 14 | $p += 8; | 
| 445 | 8 | 50 |  |  |  | 21 | $p <= length($value) or _insufficient('uint64'); | 
| 446 | 8 |  |  |  |  | 27 | return unpack_uint64( $value, $p - 8 ); | 
| 447 |  |  |  |  |  |  | } | 
| 448 |  |  |  |  |  |  | elsif ( $byte == 0xd3 ) { # int64 | 
| 449 | 21 |  |  |  |  | 33 | $p += 8; | 
| 450 | 21 | 50 |  |  |  | 40 | $p <= length($value) or _insufficient('int64'); | 
| 451 | 21 |  |  |  |  | 51 | return unpack_int64( $value, $p - 8 ); | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  | elsif ( $byte == 0xd2 ) { # int32 | 
| 454 | 38 |  |  |  |  | 60 | $p += 4; | 
| 455 | 38 | 50 |  |  |  | 75 | $p <= length($value) or _insufficient('int32'); | 
| 456 | 38 |  |  |  |  | 82 | return unpack_int32( $value, $p - 4 ); | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  | elsif ( $byte == 0xd1 ) { # int16 | 
| 459 | 34 |  |  |  |  | 59 | $p += 2; | 
| 460 | 34 | 50 |  |  |  | 95 | $p <= length($value) or _insufficient('int16'); | 
| 461 | 34 |  |  |  |  | 81 | return unpack_int16( $value, $p - 2 ); | 
| 462 |  |  |  |  |  |  | } | 
| 463 |  |  |  |  |  |  | elsif ( $byte == 0xd0 ) { # int8 | 
| 464 | 46 |  |  |  |  | 63 | $p++; | 
| 465 | 46 | 50 |  |  |  | 87 | $p <= length($value) or _insufficient('int8'); | 
| 466 | 46 |  |  |  |  | 170 | return CORE::unpack 'c',  substr( $value, $p - 1, 1 ); | 
| 467 |  |  |  |  |  |  | } | 
| 468 |  |  |  |  |  |  | elsif ( $byte == 0xcb ) { # double | 
| 469 | 112 |  |  |  |  | 139 | $p += 8; | 
| 470 | 112 | 50 |  |  |  | 234 | $p <= length($value) or _insufficient('double'); | 
| 471 | 112 |  |  |  |  | 210 | return unpack_double( $value, $p - 8 ); | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  | elsif ( $byte == 0xca ) { # float | 
| 474 | 4 |  |  |  |  | 6 | $p += 4; | 
| 475 | 4 | 50 |  |  |  | 11 | $p <= length($value) or _insufficient('float'); | 
| 476 | 4 |  |  |  |  | 9 | return unpack_float( $value, $p - 4 ); | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  | else { | 
| 479 | 0 |  |  |  |  | 0 | _unexpected("byte 0x%02x", $byte); | 
| 480 |  |  |  |  |  |  | } | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | # | 
| 485 |  |  |  |  |  |  | # Data::MessagePack::Unpacker | 
| 486 |  |  |  |  |  |  | # | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | package | 
| 489 |  |  |  |  |  |  | Data::MessagePack::PP::Unpacker; | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | sub new { | 
| 492 | 37 |  |  | 37 |  | 41086 | bless { | 
| 493 |  |  |  |  |  |  | pos  => 0, | 
| 494 |  |  |  |  |  |  | utf8 => 0, | 
| 495 |  |  |  |  |  |  | buff => '', | 
| 496 |  |  |  |  |  |  | }, shift; | 
| 497 |  |  |  |  |  |  | } | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | sub utf8 { | 
| 500 | 2 |  |  | 2 |  | 610 | my $self = shift; | 
| 501 | 2 | 100 |  |  |  | 8 | $self->{utf8} = (@_ ? shift : 1); | 
| 502 | 2 |  |  |  |  | 10 | return $self; | 
| 503 |  |  |  |  |  |  | } | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | sub get_utf8 { | 
| 506 | 4 |  |  | 4 |  | 1357 | my($self) = @_; | 
| 507 | 4 |  |  |  |  | 16 | return $self->{utf8}; | 
| 508 |  |  |  |  |  |  | } | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | sub execute_limit { | 
| 511 | 0 |  |  | 0 |  | 0 | execute( @_ ); | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | sub execute { | 
| 515 | 1706 |  |  | 1706 |  | 174399 | my ( $self, $data, $offset, $limit ) = @_; | 
| 516 | 1706 |  | 100 |  |  | 5100 | $offset ||= 0; | 
| 517 | 1706 | 50 |  |  |  | 3742 | my $value = substr( $data, $offset, $limit ? $limit : length $data ); | 
| 518 | 1706 |  |  |  |  | 1958 | my $len   = length $value; | 
| 519 |  |  |  |  |  |  |  | 
| 520 | 1706 |  |  |  |  | 2780 | $self->{buff} .= $value; | 
| 521 | 1706 |  |  |  |  | 2891 | local $self->{stack} = []; | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | #$p = 0; | 
| 524 |  |  |  |  |  |  | #eval { Data::MessagePack::PP::_unpack($self->{buff}) }; | 
| 525 |  |  |  |  |  |  | #warn "[$p][$@]"; | 
| 526 | 1706 |  |  |  |  | 2120 | $p = 0; | 
| 527 |  |  |  |  |  |  |  | 
| 528 | 1706 |  |  |  |  | 2845 | while ( length($self->{buff}) > $p ) { | 
| 529 | 20059 | 50 |  |  |  | 26439 | _count( $self, $self->{buff} ) or last; | 
| 530 |  |  |  |  |  |  |  | 
| 531 | 20059 |  | 100 |  |  | 22050 | while ( @{ $self->{stack} } > 0 && --$self->{stack}->[-1] == 0) { | 
|  | 22527 |  |  |  |  | 55955 |  | 
| 532 | 2468 |  |  |  |  | 2754 | pop @{ $self->{stack} }; | 
|  | 2468 |  |  |  |  | 3219 |  | 
| 533 |  |  |  |  |  |  | } | 
| 534 |  |  |  |  |  |  |  | 
| 535 | 20059 | 100 |  |  |  | 22302 | if (@{$self->{stack}} == 0) { | 
|  | 20059 |  |  |  |  | 37811 |  | 
| 536 | 1281 |  |  |  |  | 1452 | $self->{is_finished}++; | 
| 537 | 1281 |  |  |  |  | 1485 | last; | 
| 538 |  |  |  |  |  |  | } | 
| 539 |  |  |  |  |  |  | } | 
| 540 | 1706 |  |  |  |  | 2096 | $self->{pos} = $p; | 
| 541 |  |  |  |  |  |  |  | 
| 542 | 1706 |  |  |  |  | 4450 | return $p + $offset; | 
| 543 |  |  |  |  |  |  | } | 
| 544 |  |  |  |  |  |  |  | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | sub _count { | 
| 547 | 20059 |  |  | 20059 |  | 27909 | my ( $self, $value ) = @_; | 
| 548 | 25 |  |  | 25 |  | 169 | no warnings; # FIXME | 
|  | 25 |  |  |  |  | 52 |  | 
|  | 25 |  |  |  |  | 14762 |  | 
| 549 | 20059 |  |  |  |  | 30331 | my $byte = unpack( 'C', substr( $value, $p++, 1 ) ); # get header | 
| 550 |  |  |  |  |  |  |  | 
| 551 | 20059 | 50 |  |  |  | 31033 | Carp::croak('invalid data') unless defined $byte; | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | # +/- fixnum, nil, true, false | 
| 554 | 20059 | 100 |  |  |  | 35103 | return 1 if $typemap[$byte] & $T_DIRECT; | 
| 555 |  |  |  |  |  |  |  | 
| 556 | 10562 | 100 | 100 |  |  | 27148 | if ( $typemap[$byte] & $T_STR ) { | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 557 | 35 |  |  |  |  | 45 | my $num; | 
| 558 | 35 | 100 |  |  |  | 81 | if ( $byte == 0xd9 ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 559 | 1 |  |  |  |  | 3 | $num = unpack 'C', substr( $value, $p, 1 ); | 
| 560 | 1 |  |  |  |  | 3 | $p += 1; | 
| 561 |  |  |  |  |  |  | } | 
| 562 |  |  |  |  |  |  | elsif ( $byte == 0xda ) { | 
| 563 | 6 |  |  |  |  | 15 | $num = unpack 'n', substr( $value, $p, 2 ); | 
| 564 | 6 |  |  |  |  | 8 | $p += 2; | 
| 565 |  |  |  |  |  |  | } | 
| 566 |  |  |  |  |  |  | elsif ( $byte == 0xdb ) { | 
| 567 | 6 |  |  |  |  | 15 | $num = unpack 'N', substr( $value, $p, 4 ); | 
| 568 | 6 |  |  |  |  | 7 | $p += 4; | 
| 569 |  |  |  |  |  |  | } | 
| 570 |  |  |  |  |  |  | else { # fix raw | 
| 571 | 22 |  |  |  |  | 32 | $num = $byte & ~0xa0; | 
| 572 |  |  |  |  |  |  | } | 
| 573 | 35 |  |  |  |  | 41 | $p += $num; | 
| 574 | 35 |  |  |  |  | 66 | return 1; | 
| 575 |  |  |  |  |  |  | } | 
| 576 |  |  |  |  |  |  | elsif ( $typemap[$byte] & $T_ARRAY ) { | 
| 577 | 2427 |  |  |  |  | 2714 | my $num; | 
| 578 | 2427 | 100 |  |  |  | 3742 | if ( $byte == 0xdc ) { # array 16 | 
|  |  | 100 |  |  |  |  |  | 
| 579 | 454 |  |  |  |  | 879 | $num = unpack 'n', substr( $value, $p, 2 ); | 
| 580 | 454 |  |  |  |  | 672 | $p += 2; | 
| 581 |  |  |  |  |  |  | } | 
| 582 |  |  |  |  |  |  | elsif ( $byte == 0xdd ) { # array 32 | 
| 583 | 5 |  |  |  |  | 12 | $num = unpack 'N', substr( $value, $p, 4 ); | 
| 584 | 5 |  |  |  |  | 10 | $p += 4; | 
| 585 |  |  |  |  |  |  | } | 
| 586 |  |  |  |  |  |  | else { # fix array | 
| 587 | 1968 |  |  |  |  | 2320 | $num = $byte & ~0x90; | 
| 588 |  |  |  |  |  |  | } | 
| 589 |  |  |  |  |  |  |  | 
| 590 | 2427 | 100 |  |  |  | 3429 | if ( $num ) { | 
| 591 | 2041 |  |  |  |  | 2164 | push @{ $self->{stack} }, $num + 1; | 
|  | 2041 |  |  |  |  | 3438 |  | 
| 592 |  |  |  |  |  |  | } | 
| 593 |  |  |  |  |  |  |  | 
| 594 | 2427 |  |  |  |  | 4487 | return 1; | 
| 595 |  |  |  |  |  |  | } | 
| 596 |  |  |  |  |  |  | elsif ( $typemap[$byte] & $T_MAP ) { | 
| 597 | 1234 |  |  |  |  | 1271 | my $num; | 
| 598 | 1234 | 100 |  |  |  | 1870 | if ( $byte == 0xde ) { # map 16 | 
|  |  | 100 |  |  |  |  |  | 
| 599 | 6 |  |  |  |  | 17 | $num = unpack 'n', substr( $value, $p, 2 ); | 
| 600 | 6 |  |  |  |  | 10 | $p += 2; | 
| 601 |  |  |  |  |  |  | } | 
| 602 |  |  |  |  |  |  | elsif ( $byte == 0xdf ) { # map 32 | 
| 603 | 6 |  |  |  |  | 14 | $num = unpack 'N', substr( $value, $p, 4 ); | 
| 604 | 6 |  |  |  |  | 22 | $p += 4; | 
| 605 |  |  |  |  |  |  | } | 
| 606 |  |  |  |  |  |  | else { # fix map | 
| 607 | 1222 |  |  |  |  | 1463 | $num = $byte & ~0x80; | 
| 608 |  |  |  |  |  |  | } | 
| 609 |  |  |  |  |  |  |  | 
| 610 | 1234 | 100 |  |  |  | 1611 | if ( $num ) { | 
| 611 | 928 |  |  |  |  | 951 | push @{ $self->{stack} }, $num * 2 + 1; # a pair | 
|  | 928 |  |  |  |  | 1362 |  | 
| 612 |  |  |  |  |  |  | } | 
| 613 |  |  |  |  |  |  |  | 
| 614 | 1234 |  |  |  |  | 2111 | return 1; | 
| 615 |  |  |  |  |  |  | } | 
| 616 |  |  |  |  |  |  | elsif ( $typemap[$byte] & $T_BIN ) { | 
| 617 | 3627 |  |  |  |  | 3795 | my $num; | 
| 618 | 3627 | 100 |  |  |  | 4843 | if ( $byte == 0xc4 ) { # bin 8 | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 619 | 2593 |  |  |  |  | 3674 | $num = unpack 'C', substr( $value, $p, 1 ); | 
| 620 | 2593 |  |  |  |  | 3027 | $p += 1; | 
| 621 |  |  |  |  |  |  | } | 
| 622 |  |  |  |  |  |  | elsif ( $byte == 0xc5 ) { # bin 16 | 
| 623 | 1028 |  |  |  |  | 1442 | $num = unpack 'n', substr( $value, $p, 2 ); | 
| 624 | 1028 |  |  |  |  | 1199 | $p += 2; | 
| 625 |  |  |  |  |  |  | } | 
| 626 |  |  |  |  |  |  | elsif ( $byte == 0xc6 ) { # bin 32 | 
| 627 | 6 |  |  |  |  | 13 | $num = unpack 'N', substr( $value, $p, 4 ); | 
| 628 | 6 |  |  |  |  | 7 | $p += 4; | 
| 629 |  |  |  |  |  |  | } | 
| 630 |  |  |  |  |  |  |  | 
| 631 | 3627 |  |  |  |  | 3768 | $p += $num; | 
| 632 | 3627 |  |  |  |  | 6098 | return 1; | 
| 633 |  |  |  |  |  |  | } | 
| 634 |  |  |  |  |  |  | elsif ( $byte >= 0xcc and $byte <= 0xcf ) { # uint | 
| 635 | 1148 | 50 |  |  |  | 2041 | $p += $byte == 0xcc ? 1 | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | : $byte == 0xcd ? 2 | 
| 637 |  |  |  |  |  |  | : $byte == 0xce ? 4 | 
| 638 |  |  |  |  |  |  | : $byte == 0xcf ? 8 | 
| 639 |  |  |  |  |  |  | : Data::MessagePack::PP::_unexpected("byte 0x%02x", $byte); | 
| 640 | 1148 |  |  |  |  | 2421 | return 1; | 
| 641 |  |  |  |  |  |  | } | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | elsif ( $byte >= 0xd0 and $byte <= 0xd3 ) { # int | 
| 644 | 1035 | 50 |  |  |  | 1884 | $p += $byte == 0xd0 ? 1 | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | : $byte == 0xd1 ? 2 | 
| 646 |  |  |  |  |  |  | : $byte == 0xd2 ? 4 | 
| 647 |  |  |  |  |  |  | : $byte == 0xd3 ? 8 | 
| 648 |  |  |  |  |  |  | : Data::MessagePack::PP::_unexpected("byte 0x%02x", $byte); | 
| 649 | 1035 |  |  |  |  | 1916 | return 1; | 
| 650 |  |  |  |  |  |  | } | 
| 651 |  |  |  |  |  |  | elsif ( $byte == 0xca or $byte == 0xcb ) { # float, double | 
| 652 | 1056 | 100 |  |  |  | 1498 | $p += $byte == 0xca ? 4 : 8; | 
| 653 | 1056 |  |  |  |  | 1934 | return 1; | 
| 654 |  |  |  |  |  |  | } | 
| 655 |  |  |  |  |  |  | else { | 
| 656 | 0 |  |  |  |  | 0 | Data::MessagePack::PP::_unexpected("byte 0x%02x", $byte); | 
| 657 |  |  |  |  |  |  | } | 
| 658 |  |  |  |  |  |  |  | 
| 659 | 0 |  |  |  |  | 0 | return 0; | 
| 660 |  |  |  |  |  |  | } | 
| 661 |  |  |  |  |  |  |  | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  | sub data { | 
| 664 | 238 |  |  | 238 |  | 603 | my($self) = @_; | 
| 665 | 238 |  |  |  |  | 407 | local $Data::MessagePack::PP::_utf8 = $self->{utf8}; | 
| 666 | 238 |  |  |  |  | 745 | return Data::MessagePack->unpack( substr($self->{buff}, 0, $self->{pos}) ); | 
| 667 |  |  |  |  |  |  | } | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  |  | 
| 670 |  |  |  |  |  |  | sub is_finished { | 
| 671 | 87 |  |  | 87 |  | 10334 | my ( $self ) = @_; | 
| 672 | 87 |  |  |  |  | 282 | return $self->{is_finished}; | 
| 673 |  |  |  |  |  |  | } | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | sub reset :method { | 
| 676 | 207 |  |  | 207 |  | 25317 | $_[0]->{buff}        = ''; | 
| 677 | 207 |  |  |  |  | 285 | $_[0]->{pos}         = 0; | 
| 678 | 207 |  |  |  |  | 349 | $_[0]->{is_finished} = 0; | 
| 679 |  |  |  |  |  |  | } | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | 1; | 
| 682 |  |  |  |  |  |  | __END__ |