File Coverage

blib/lib/Data/AMF/Formatter/AMF3.pm
Criterion Covered Total %
statement 115 143 80.4
branch 35 54 64.8
condition 3 6 50.0
subroutine 16 17 94.1
pod 1 12 8.3
total 170 232 73.2


line stmt bran cond sub pod time code
1             package Data::AMF::Formatter::AMF3;
2 7     7   39 use strict;
  7         25  
  7         489  
3 7     7   40 use warnings;
  7         13  
  7         212  
4              
5             require bytes;
6 7     7   53 use Data::AMF::IO;
  7         16  
  7         50  
7 7     7   181 use Scalar::Util qw/blessed looks_like_number/;
  7         13  
  7         637  
8              
9             # ----------------------------------------------------------------------
10             # Class Constants
11             # ----------------------------------------------------------------------
12              
13             use constant
14             {
15 7         17194 UNDEFINED_MARKER => 0x00,
16             NULL_MARKER => 0x01,
17             FALSE_MARKER => 0x02,
18             TRUE_MARKER => 0x03,
19             INTEGER_MARKER => 0x04,
20             NUMBER_MARKER => 0x05,
21             STRING_MARKER => 0x06,
22             XML_DOC_MARKER => 0x07,
23             DATE_MARKER => 0x08,
24             ARRAY_MARKER => 0x09,
25             OBJECT_MARKER => 0x0A,
26             XML_MARKER => 0x0B,
27             BYTE_ARRAY_MARKER => 0x0C,
28             AMF3_INTEGER_MIN => "-268435456",
29             AMF3_INTEGER_MAX => "268435455"
30 7     7   43 };
  7         14  
31              
32             # ----------------------------------------------------------------------
33             # Class Methods
34             # ----------------------------------------------------------------------
35              
36             sub format
37             {
38 11     11 1 22 my ($class, $object) = @_;
39            
40 11         33 my $self = $class->new;
41            
42 11         30 $self->write($object);
43            
44 11         30 return $self->io->data;
45             }
46              
47             # ----------------------------------------------------------------------
48             # Constructor
49             # ----------------------------------------------------------------------
50              
51             sub new
52             {
53 11     11 0 14 my $class = shift;
54 11         174 my $self = bless {
55             io => Data::AMF::IO->new( data => q[] ),
56             stored_objects_count => 0,
57             stored_objects => {},
58             stored_strings_count => 0,
59             stored_strings => {},
60             @_
61             }, $class;
62 11         128 return $self;
63             }
64              
65             # ----------------------------------------------------------------------
66             # Properties
67             # ----------------------------------------------------------------------
68              
69 104     104 0 430 sub io { return $_[0]->{'io'} }
70              
71             # ----------------------------------------------------------------------
72             # Methods
73             # ----------------------------------------------------------------------
74              
75             sub write
76             {
77 28     28 0 41 my ($self, $value) = @_;
78            
79 28 100       132 if (my $pkg = blessed $value)
    100          
80             {
81 5 100       26 if ($pkg eq 'Data::AMF::Type::Boolean')
    100          
    100          
    50          
    0          
82             {
83 2 100       8 if ($value->data)
84             {
85 1         4 $self->io->write_u8(TRUE_MARKER);
86             }
87             else
88             {
89 1         4 $self->io->write_u8(FALSE_MARKER);
90             }
91             }
92             elsif ($pkg eq 'Data::AMF::Type::ByteArray')
93             {
94 1         5 $self->io->write_u8(BYTE_ARRAY_MARKER);
95 1         8 $self->write_byte_array($value);
96             }
97             elsif ($pkg eq 'Data::AMF::Type::Null')
98             {
99 1         4 $self->io->write_u8(NULL_MARKER);
100             }
101             elsif ($pkg eq 'DateTime')
102             {
103 1         4 $self->io->write_u8(DATE_MARKER);
104 1         6 $self->write_date($value);
105             }
106             elsif ($pkg eq 'XML::LibXML::Document')
107             {
108 0         0 $self->io->write_u8(XML_MARKER);
109 0         0 $self->write_xml($value);
110             }
111             else
112             {
113 0         0 $self->io->write_u8(OBJECT_MARKER);
114 0         0 $self->write_object($value);
115             }
116             }
117             elsif (my $ref = ref($value))
118             {
119 8 100       24 if ($ref eq 'ARRAY')
    50          
120             {
121 1         4 $self->io->write_u8(ARRAY_MARKER);
122 1         5 $self->write_array($value);
123             }
124             elsif ($ref eq 'HASH')
125             {
126 7         16 $self->io->write_u8(OBJECT_MARKER);
127 7         26 $self->write_object($value);
128             }
129             else
130             {
131 0         0 die qq[cannot format "$ref" object];
132             }
133             }
134             else
135             {
136 15 100       58 if (looks_like_number($value))
    100          
137             {
138 5 100 33     42 if ($value >= AMF3_INTEGER_MIN && $value <= AMF3_INTEGER_MAX && $value == int($value))
      66        
139             {
140 4         11 $self->io->write_u8(INTEGER_MARKER);
141 4         11 $self->write_integer($value);
142             }
143             else
144             {
145 1         5 $self->io->write_u8(NUMBER_MARKER);
146 1         5 $self->write_number($value);
147             }
148             }
149             elsif (defined $value)
150             {
151 9         20 $self->io->write_u8(STRING_MARKER);
152 9         25 $self->write_string($value);
153             }
154             else
155             {
156 1         5 $self->io->write_u8(UNDEFINED_MARKER);
157             }
158             }
159             }
160              
161             sub write_integer
162             {
163 27     27 0 38 my ($self, $value) = @_;
164            
165 27         31 $value = $value & 0x1fffffff;
166            
167 27 50       50 if ($value < 0x80)
    0          
    0          
168             {
169 27         52 $self->io->write_u8($value);
170             }
171             elsif ($value < 0x4000)
172             {
173 0         0 $self->io->write(
174             pack('C', $value >> 7 & 0x7f | 0x80)
175             . pack('C', $value & 0x7f)
176             );
177             }
178             elsif ($value < 0x200000)
179             {
180 0         0 $self->io->write(
181             pack('C', $value >> 14 & 0x7f | 0x80)
182             . pack('C', $value >> 7 & 0x7f | 0x80)
183             . pack('C', $value & 0x7f)
184             );
185             }
186             else
187             {
188 0         0 $self->io->write(
189             pack('C', $value >> 22 & 0x7f | 0x80)
190             . pack('C', $value >> 15 & 0x7f | 0x80)
191             . pack('C', $value >> 8 & 0x7f | 0x80)
192             . pack('C', $value & 0xff)
193             );
194             }
195             }
196              
197             sub write_number
198             {
199 1     1 0 2 my ($self, $value) = @_;
200 1         3 $self->io->write_double($value);
201             }
202              
203             sub write_string
204             {
205 20     20 0 28 my ($self, $value) = @_;
206            
207 20         32 my $i = $self->{'stored_strings'}->{$value};
208            
209 20 100       30 if (defined $i)
210             {
211 7 50       15 if ($value eq '')
212             {
213 0         0 $self->io->write_u8(NULL_MARKER);
214             }
215             else
216             {
217 7         11 my $reference = $i << 1;
218 7         16 $self->write_integer($reference);
219             }
220             }
221             else
222             {
223 13 100       32 if ($value ne '') {
224 11         28 $self->{'stored_strings'}->{$value} = $self->{'stored_strings_count'};
225 11         13 $self->{'stored_strings_count'}++;
226             }
227              
228 13         17 my $reference = length $value;
229 13         17 $reference = $reference << 1 | 1;
230            
231 13         28 $self->write_integer($reference);
232 13         29 $self->io->write($value);
233             }
234             }
235              
236             sub write_array
237             {
238 1     1 0 3 my ($self, $value) = @_;
239            
240 1         2 my $i = $self->{'stored_objects'}->{$value};
241            
242 1 50       4 if (defined $i)
243             {
244 0         0 my $reference = $i << 1;
245 0         0 $self->write_integer($reference);
246             }
247             else
248             {
249 1         4 $self->{'stored_objects'}->{$value} = $self->{'stored_objects_count'};
250 1         2 $self->{'stored_objects_count'}++;
251            
252 1         2 my $reference = @{ $value };
  1         3  
253 1         2 $reference = $reference << 1 | 0x01;
254            
255 1         3 $self->write_integer($reference);
256 1         3 $self->io->write_u8(NULL_MARKER);
257            
258 1         2 for my $v (@{ $value })
  1         3  
259             {
260 6         16 $self->write($v);
261             }
262             }
263             }
264              
265             sub write_object
266             {
267 7     7 0 10 my ($self, $value) = @_;
268            
269 7         17 my $i = $self->{'stored_objects'}->{$value};
270            
271 7 50       27 if (defined $i)
272             {
273            
274 0         0 my $reference = $i << 1;
275 0         0 $self->write_integer($reference);
276             }
277             else
278             {
279 7         25 $self->{'stored_objects'}->{$value} = $self->{'stored_objects_count'};
280 7         9 $self->{'stored_objects_count'}++;
281            
282 7         17 $self->io->write_u8(0x0B); # U29o-traits (ダイナミッククラス)
283            
284 7 50       18 if (defined $value->{'_explicitType'})
285             {
286 0         0 $self->write_string($value->{'_explicitType'});
287             }
288             else
289             {
290 7         14 $self->io->write_u8(NULL_MARKER); # 匿名クラスの場合は空ストリング
291             }
292            
293 7         13 for my $k (keys %{ $value })
  7         25  
294             {
295 11 50       56 next if $k eq '_explicitType';
296            
297 11         24 $self->write_string($k);
298            
299 11         21 my $v = $value->{$k};
300            
301 11 50       18 if (defined $v)
302             {
303 11         36 $self->write($value->{$k});
304             }
305             else
306             {
307 0         0 $self->io->write_u8(NULL_MARKER);
308             }
309            
310             }
311            
312 7         20 $self->io->write_u8(NULL_MARKER);
313             }
314             }
315              
316             sub write_byte_array
317             {
318 1     1 0 3 my ($self, $value) = @_;
319            
320 1         4 my $i = $self->{'stored_objects'}->{$value};
321            
322 1 50       4 if (defined $i)
323             {
324 0         0 my $reference = $i << 1;
325 0         0 $self->write_integer($reference);
326             }
327             else
328             {
329 1         5 $self->{'stored_objects'}->{$value} = $self->{'stored_objects_count'};
330 1         2 $self->{'stored_objects_count'}++;
331            
332 1         6 my $data = $value->data;
333 1         3 my $length = scalar @$data;
334 1         5 my $bin = pack('C' . $length, @$data);
335 1         3 my $reference = $length << 1 | 1;
336            
337 1         4 $self->write_integer($reference);
338 1         4 $self->io->write($bin);
339             }
340             }
341              
342             sub write_date
343             {
344 1     1 0 4 my ($self, $value) = @_;
345            
346 1         5 my $i = $self->{'stored_objects'}->{$value};
347            
348 1 50       27 if (defined $i)
349             {
350 0         0 my $reference = $i << 1;
351 0         0 $self->write_integer($reference);
352             }
353             else
354             {
355 1         5 $self->{'stored_objects'}->{$value} = $self->{'stored_objects_count'};
356 1         24 $self->{'stored_objects_count'}++;
357            
358 1         5 $self->write_integer(1);
359 1         8 my $msec = $value->epoch * 1000;
360 1         14 $self->io->write_double($msec);
361             }
362             }
363              
364             sub write_xml
365             {
366 0     0 0   my ($self, $value) = @_;
367            
368 0           my $i = $self->{'stored_objects'}->{$value};
369            
370 0 0         if (defined $i)
371             {
372 0           my $reference = $i << 1;
373 0           $self->write_integer($reference);
374             }
375             else
376             {
377 0           $self->{'stored_objects'}->{$value} = $self->{'stored_objects_count'};
378 0           $self->{'stored_objects_count'}++;
379              
380 0           my $obj = $value->toString();
381 0           $self->write_string($obj);
382             }
383             }
384              
385             =head1 NAME
386              
387             Data::AMF::Formatter::AMF3 - AMF3 serializer
388              
389             =head1 SYNOPSIS
390              
391             my $amf3_data = Data::AMF::Formatter::AMF3->format($obj);
392              
393             =head1 METHODS
394              
395             =head2 format
396              
397             =head1 AUTHOR
398              
399             Takuho Yoshizu
400              
401             =head1 COPYRIGHT
402              
403             This program is free software; you can redistribute
404             it and/or modify it under the same terms as Perl itself.
405              
406             The full text of the license can be found in the
407             LICENSE file included with this module.
408              
409             =cut
410              
411             1;
412