File Coverage

blib/lib/Hessian/Tiny/ConvertorV1.pm
Criterion Covered Total %
statement 166 498 33.3
branch 67 146 45.8
condition 0 6 0.0
subroutine 18 24 75.0
pod 1 1 100.0
total 252 675 37.3


line stmt bran cond sub pod time code
1             package Hessian::Tiny::ConvertorV1;
2              
3 2     2   13 use warnings;
  2         4  
  2         268  
4 2     2   13 use strict;
  2         3  
  2         67  
5              
6 2     2   3222 use Encode ();
  2         46148  
  2         179  
7 2     2   4607 use Switch 'Perl6';
  2         131777  
  2         15  
8 2     2   1006832 use List::Util qw(first);
  2         6  
  2         302  
9 2     2   16 use IO::Handle ();
  2         5  
  2         38  
10 2     2   14 use Scalar::Util ();
  2         4  
  2         36  
11 2     2   3829 use Math::BigInt ();
  2         76026  
  2         108  
12 2     2   2299 use Tie::RefHash ();
  2         23016  
  2         65  
13              
14 2     2   1257 use Hessian::Tiny::Type ();
  2         6  
  2         9942  
15              
16             =head1 NAME
17              
18             Hessian::Tiny::ConvertorV1 - v1 serializer/deserializer
19              
20             =head1 SUBROUTINES/METHODS
21              
22             =head2 write_call
23              
24             write hessian v1 call string
25              
26             =cut
27              
28             sub write_call {
29 183     183 1 514 my($writer,$method_name,@hessian_params) = @_;
30 183         653 $writer->("c\x01\x00m");
31 183         1557 $writer->(pack 'n', length $method_name);
32 183         731 $writer->($method_name,1);
33 183         547 my $serializer_v1 = _make_serializer_v1($writer);
34 183         5527 $serializer_v1->($_) for(@hessian_params);
35 183         816 $writer->('z');
36             }
37             sub __write_reply { # for future server use
38 0     0   0 my($writer,$value) = @_;
39 0         0 $writer->("r\x01\x00");
40 0         0 my $serializer_v1 = _make_serializer_v1($writer);
41 0         0 $serializer_v1->($value);
42 0         0 $writer->('z');
43             }
44             sub _make_serializer_v1 {
45 183     183   579 my($wr) = @_;
46 183         704 my $refs = [];
47 183         337 my $f;
48             $f = sub {
49 59     59   125 my $x = shift;
50 59         116 my $rf = \$f;
51 59         343 Scalar::Util::weaken($rf);
52 59 50       223 unless(defined $x){ $wr->('N'); return}
  0         0  
  0         0  
53 59         105 given(ref $x){
  59         219  
  59         365  
  0         0  
54 59 100       1321 when('Hessian::Type::Null') { $wr->('N') }
  1         18  
  1         5  
  1         10  
  0         0  
  0         0  
  0         0  
55 58 100       1742 when('Hessian::Type::True') { $wr->('T') }
  1         15  
  1         6  
  1         11  
  0         0  
  0         0  
  0         0  
56 57 100       2481 when('Hessian::Type::False') { $wr->('F') }
  1         17  
  1         4  
  1         10  
  0         0  
  0         0  
  0         0  
57 56 100       1488 when('Hessian::Type::Date') { $wr->('d');
  3         36  
  3         12  
58 3 50       34 $wr->('Math::BigInt' eq ref $$x{data}
59             ? Hessian::Tiny::Type::_pack_q($$x{data})
60             : Hessian::Tiny::Type::_l2n(pack 'q', $$x{data})
61             );
62 3         33 }
  0         0  
  0         0  
  0         0  
63 53 50       800 when('DateTime') { $wr->('d'.Hessian::Tiny::Type::_pack_q(Math::BigInt->new($x->epoch)->bmul(1000)))}
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
64              
65 53 100       802 when('Hessian::Type::Integer') { $wr->('I' . Hessian::Tiny::Type::_l2n(pack 'l', $$x{data})) }
  16         221  
  16         442  
  16         229  
  0         0  
  0         0  
  0         0  
66 37 50       518 when('Hessian::Type::Long') { $wr->('L' . Hessian::Tiny::Type::_pack_q($$x{data})) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
67 37 100       563 when('Math::BigInt') { $wr->('L' . Hessian::Tiny::Type::_pack_q($x)) }
  18         218  
  18         86  
  18         227  
  0         0  
  0         0  
  0         0  
68 19 100       1310 when('Hessian::Type::Double') { $wr->('D' . Hessian::Tiny::Type::_l2n(pack 'd', $$x{data})) }
  13         335  
  13         119  
  13         168  
  0         0  
  0         0  
  0         0  
69              
70 6 50       89 when('Hessian::Type::Binary') { _write_chunks($wr,$$x{data}) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
71 6 50       85 when('Hessian::Type::String') { _write_chunks($wr,$$x{data},1) }
  6         78  
  6         32  
  6         67  
  0         0  
  0         0  
  0         0  
72 0 0       0 when('Unicode::String') { _write_chunks($wr,$x->as_string,1) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
73 0 0       0 when('Hessian::Type::XML') { _write_xml($wr,$x->as_string) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
74              
75 0 0       0 when('Hessian::Type::List') { my $idx = _search_ref($refs,$x);
  0         0  
  0         0  
76 0 0       0 if(defined $idx){
77 0         0 $wr->('R' . Hessian::Tiny::Type::_l2n(pack 'l', $idx));
78             }else{
79 0         0 push @$refs,$x;
80 0         0 _write_list($$rf,$wr,$x);
81             }
82 0         0 }
  0         0  
  0         0  
  0         0  
83 0 0       0 when('ARRAY') { my $idx = _search_ref($refs,$x);
  0         0  
  0         0  
84 0 0       0 if(defined $idx){
85 0         0 $wr->('R' . Hessian::Tiny::Type::_l2n(pack 'l', $idx));
86             }else{
87 0         0 push @$refs,$x;
88 0         0 my $y = Hessian::Type::List->new(length=>scalar @$x,data=>$x);
89 0         0 _write_list($$rf,$wr,$y);
90             }
91 0         0 }
  0         0  
  0         0  
  0         0  
92 0 0       0 when('Hessian::Type::Map') { my $idx = _search_ref($refs,$x);
  0         0  
  0         0  
93 0 0       0 if(defined $idx){
94 0         0 $wr->('R' . Hessian::Tiny::Type::_l2n(pack 'l', $idx));
95             }else{
96 0         0 push @$refs,$x;
97 0         0 _write_map($$rf,$wr,$x);
98             }
99 0         0 }
  0         0  
  0         0  
  0         0  
100 0 0       0 when('Hessian::Type::Fault') {
  0         0  
101 0         0 }
  0         0  
  0         0  
  0         0  
102 0 0       0 when('HASH') { my $idx = _search_ref($refs,$x);
  0         0  
  0         0  
103 0 0       0 if(defined $idx){
104 0         0 $wr->('R' . Hessian::Tiny::Type::_l2n(pack 'l', $idx));
105             }else{
106 0         0 push @$refs,$x;
107 0         0 my $y = Hessian::Type::Map->new($x);
108 0         0 _write_map($$rf,$wr,$x);
109             }
110 0         0 }
  0         0  
  0         0  
  0         0  
111             #when('Hessian::Type::Remote') { _write_remote($wr,$x) }
112             #when('Hessian::Type::Fault') { _write_fault($wr,$x) }
113 0 0       0 when('REF') { $wr->('R' . Hessian::Tiny::Type::_l2n(pack'l', first{$$x == $$refs[$_]}(0 .. $#$refs))) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
114              
115 0 0       0 when('') { # guessing begins
  0         0  
116 0         0 given($x){
  0         0  
  0         0  
  0         0  
117 0 0       0 when /^[\+\-]?(0x)?\d+$/ { my $bi = Math::BigInt->new($x);
  0         0  
  0         0  
118 0 0 0     0 if(Math::BigInt->new('-0x80000000')->bcmp($bi) <= 0 &&
    0 0        
119             Math::BigInt->new(' 0x7fffffff')->bcmp($bi) >= 0
120             ){ # Integer
121 0         0 $wr->('I' . Hessian::Tiny::Type::_l2n(pack 'l', $x));
122             }elsif(Math::BigInt->new('-0x8000000000000000')->bcmp($bi) <=0 &&
123             Math::BigInt->new(' 0x7fffffffffffffff')->bcmp($bi) >=0
124             ){ # Long
125 0         0 $wr->('L' . Hessian::Tiny::Type::_pack_q($x));
126             }else{ # too large to be number
127 0         0 _write_chunks($wr,$x,Encode::is_utf8($x,1));
128             }
129 0         0 }
  0         0  
  0         0  
  0         0  
130 0 0       0 when /^[\+\-]?\d*(\d+\.|\.\d+)\d*$/ { $wr->('D' . Hessian::Tiny::Type::_l2n(pack 'd', $x)) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
131 0 0       0 when /\D/ { _write_chunks($wr,$x,Encode::is_utf8($x,1)) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
132             }
133 0         0 }
  0         0  
  0         0  
  0         0  
134 0         0 default { die "_serialize_v1: unrecognized type (@{[ref $x]})" }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
135             } # end given
136 183         3151 };
137 183         515 return $f;
138             }
139             sub _search_ref { # return index, or undef if not found
140 0     0   0 my($refs,$r) = @_;
141 0         0 for my $i (0 .. $#$refs){
142 0 0       0 return $i if $refs->[$i] == $r;
143             }
144 0         0 return undef;
145             }
146             sub _write_xml {
147 0     0   0 my($wr,$str) = @_;
148 0 0       0 if(length $str > 0x7fff){
149 0         0 $wr->('x');
150 0         0 $wr->("\x7f\xff");
151 0         0 $wr->(substr($str,0,0x7fff));
152 0         0 _write_xml($wr,substr($str,0x7fff));
153             }else{
154 0         0 $wr->('X');
155 0         0 $wr->(pack('n',length $str));
156 0         0 $wr->($str);
157             }
158             }
159             sub _write_chunks {
160 6     6   20 my($wr,$str,$utf8) = @_;
161 6 50       39 if(length $str > 0x7fff){
162 0 0       0 $wr->($utf8 ? 's' : 'b');
163 0         0 $wr->("\x7f\xff");
164 0         0 $wr->(substr($str,0,0x7fff), $utf8);
165 0         0 _write_chunks($wr,substr($str,0x7fff),$utf8);
166             }else{
167 6 50       79 $wr->($utf8 ? 'S' : 'B');
168 6         32 $wr->(pack('n',length $str));
169 6         22 $wr->($str, $utf8);
170             }
171             }
172              
173             sub _write_list { # 'Hessian::Type::List'
174 0     0   0 my($f,$wr,$x) = @_;
175 0         0 $wr->('V');
176 0 0       0 if($$x{type}){
177 0         0 $wr->('t' . pack('n', length $$x{type}));
178 0         0 $wr->($$x{type},1);
179             }
180 0 0       0 $wr->('l' . pack('N', $$x{length})) if($$x{length});
181 0         0 $f->($_) for(@{$$x{data}});
  0         0  
182 0         0 $wr->('z');
183             }
184              
185             sub _write_map { # 'Hessian::Type::Map'
186 0     0   0 my($f,$wr,$x) = @_;
187              
188 0         0 $wr->('M');
189 0 0       0 if($$x{type}){
190 0         0 $wr->('t' . pack('n', length $$x{type}));
191 0         0 $wr->($$x{type},1);
192             }
193 0 0       0 my @ar = 'HASH' eq ref $$x{data} ? (%{$$x{data}}) : (@{$$x{data}});
  0         0  
  0         0  
194 0         0 $f->($_) for(@ar);
195 0         0 $wr->('z');
196             }
197              
198             # de-serializer
199             sub _make_object_reader {
200 183     183   623 my $h_flg=shift; # return all hessian structure
201 183         605 my $refs = [];
202 183         305 my $f;
203             $f = sub {
204 187     187   647 my($rd,$h_flg_override) = @_;
205 187 100       683 $h_flg_override = $h_flg unless defined $h_flg_override;
206 187         429 my $rf = \$f;
207 187         982 Scalar::Util::weaken($rf);
208 187         395 given($rd->(1)){
  187         398  
  187         1145  
  0         0  
209 187 100       7533 when('N') { return $h_flg_override ? Hessian::Type::Null->new() : undef }
  5 100       480  
  5         88  
  0         0  
  0         0  
  0         0  
  0         0  
210 182 100       5214 when('T') { return $h_flg_override ? Hessian::Type::True->new() : 1 }
  61 100       989  
  61         779  
  0         0  
  0         0  
  0         0  
  0         0  
211 121 100       1826 when('F') { return $h_flg_override ? Hessian::Type::False->new() : undef }
  2 100       26  
  2         35  
  0         0  
  0         0  
  0         0  
  0         0  
212              
213 119 100       2002 when('I') { my $i = unpack 'l', Hessian::Tiny::Type::_l2n($rd->(4));
  32         536  
  32         129  
214 32 100       617 return $h_flg_override
215             ? Hessian::Type::Integer->new($i)
216             : $i
217             ;
218 0         0 } # int
  0         0  
  0         0  
  0         0  
219 87 100       1388 when('L') { my $l = Hessian::Tiny::Type::_unpack_q($rd->(8));
  36         468  
  36         160  
220 36 100       592 return $h_flg_override
221             ? $l
222             : $l->bstr
223             ;
224 0         0 } # long
  0         0  
  0         0  
  0         0  
225 51 100       816 when('D') { my $i = unpack 'd', Hessian::Tiny::Type::_l2n($rd->(8));
  26         2014  
  26         100  
226 26 100       445 return $h_flg_override
227             ? Hessian::Type::Double->new($i)
228             : $i
229             ;
230 0         0 } # double
  0         0  
  0         0  
  0         0  
231 25 100       1009 when('d') { my$msec = Hessian::Tiny::Type::_unpack_q($rd->(8));
  6         70  
  6         22  
232 6 100       75 return $h_flg_override
233             ? Hessian::Type::Date->new($msec)
234             : $msec->bdiv(1000)->bstr
235             ;
236 0         0 } # date
  0         0  
  0         0  
  0         0  
237 19 100       549 when /([BbSsXx])/ { $rd->(-1);
  18         795  
  18         3656  
238 18         58 my $t = $rd->(1);
239 18         66 $rd->(-1);
240 18         69 my $chunks = _read_chunks($rd);
241 16 100       208 return $chunks unless $h_flg_override;
242 6         16 given($t){
  6         12  
  6         25  
  0         0  
243 6 50       129 when /[Bb]/ { return Hessian::Type::Binary->new($chunks) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
244 6 50       165 when /[Ss]/ { return Hessian::Type::String->new($chunks) }
  6         110  
  6         83  
  0         0  
  0         0  
  0         0  
  0         0  
245 0 0       0 when /[Xx]/ { return Hessian::Type::XML->new($chunks) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
246             }
247 0         0 } # string/binary/xml
  0         0  
  0         0  
  0         0  
248 1 50       425 when('V') { my $v = Hessian::Type::List->new([]);
  0         0  
  0         0  
249 0 0       0 my $res = $h_flg_override ? $v : $v->{data};
250 0         0 push @$refs, $res;
251 0         0 _read_list($$rf,$rd, $v);
252 0         0 return $res;
253 0         0 } # list
  0         0  
  0         0  
  0         0  
254 1 50       17 when('M') { tie my %h, 'Tie::RefHash::Nestable';
  0         0  
  0         0  
255 0         0 my $m = Hessian::Type::Map->new(\%h);
256 0 0       0 my $res = $h_flg_override ? $m : $m->{data};
257 0         0 push @$refs, $res;
258 0         0 _read_map( $$rf,$rd,$m,$h_flg_override);
259 0         0 return $res;
260 0         0 } # map
  0         0  
  0         0  
  0         0  
261 1 50       14 when('R') { return $refs->[unpack 'l', Hessian::Tiny::Type::_l2n($rd->(4))] }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
262 1 50       16 when('H') { tie my %h, 'Tie::RefHash::Nestable';
  0         0  
  0         0  
263 0         0 my $hdr = Hessian::Type::Header->new(\%h);
264 0         0 _read_map($$rf,$rd, $hdr);
265 0         0 return $hdr;
266 0         0 } # header
  0         0  
  0         0  
  0         0  
267 1 50       15 when('r') { tie my %h, 'Tie::RefHash::Nestable';
  0         0  
  0         0  
268 0         0 my $r = Hessian::Type::Remote->new(\%h);
269 0         0 _read_map($$rf,$rd, $r);
270 0         0 return $r;
271 0         0 } # remote
  0         0  
  0         0  
  0         0  
272 1 50       33 when('f') { tie my %h, 'Tie::RefHash::Nestable';
  1         14  
  1         19  
273 1         34 my $fault = Hessian::Type::Fault->new(\%h);
274 1         6 _read_map($$rf,$rd,$fault,0);
275 1         32 return bless $fault->{data},'Hessian::Type::Fault';
276 0         0 } # fault
  0         0  
  0         0  
  0         0  
277 0 0       0 when('z') { die "_reader: z encountered" }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
278 0         0 default { die "_reader: unknown type $_" }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
279             }
280 183         3397 };
281 183         1071 return $f;
282             }
283             sub _read_chunks {
284 18     18   33 my($rd) = @_;
285 18         61 my $marker = $rd->(1);
286 18         55 my $len = unpack('n', $rd->(2));
287 18 100       74 if($marker =~ /[bsx]/){
288 2         13 return $rd->($len, $marker =~ /[sx]/) . _read_chunks($rd);
289             }else{
290 16         89 return $rd->($len, $marker =~ /[SX]/);
291             }
292             }
293             sub _read_list {
294 0     0   0 my($obj_reader,$rd,$list) = @_;
295 0 0       0 if('t' eq $rd->(1)){
296 0         0 my $len = unpack('n', $rd->(2));
297 0         0 $list->{type} = $rd->($len,1);
298 0         0 }else{ $rd->(-1) }
299              
300 0 0       0 if('l' eq $rd->(1)){
301 0         0 $list->{length} = unpack 'l', Hessian::Tiny::Type::_l2n($rd->(4));
302 0         0 }else{ $rd->(-1) }
303              
304 0         0 while('z' ne $rd->(1)){
305 0         0 $rd->(-1);
306 0         0 push @{$$list{data}}, $obj_reader->($rd);
  0         0  
307             }
308 0         0 return $list;
309             }
310             sub _read_map {
311 1     1   4 my($obj_reader,$rd,$map,$hflg) = @_;
312 1 50       5 if('t' eq $rd->(1)){
313 0         0 my $len = unpack('n', $rd->(2));
314 0         0 $map->{type} = $rd->($len,1);
315 1         5 }else{ $rd->(-1) }
316              
317 1         5 while('z' ne $rd->(1)){
318 2         9 $rd->(-1);
319 2         14 my $k = $obj_reader->($rd,$hflg);
320 2         13 $map->{data}->{$k} = $obj_reader->($rd,$hflg);
321             }
322 1         4 return $map;
323             }
324              
325             1; # End of Hessian::Tiny::ConvertorV1