File Coverage

blib/lib/Data/MessagePack/PP.pm
Criterion Covered Total %
statement 278 350 79.4
branch 183 236 77.5
condition 30 54 55.5
subroutine 34 39 87.1
pod 0 2 0.0
total 525 681 77.0


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__