File Coverage

blib/lib/SWF/Element.pm
Criterion Covered Total %
statement 566 2333 24.2
branch 116 634 18.3
condition 27 205 13.1
subroutine 94 316 29.7
pod 8 10 80.0
total 811 3498 23.1


line stmt bran cond sub pod time code
1             package SWF::Element;
2            
3             require 5.006;
4            
5 1     1   14474 use strict;
  1         3  
  1         81  
6 1     1   5 use vars qw($VERSION @ISA);
  1         3  
  1         82  
7            
8 1     1   6 use Carp;
  1         19  
  1         120  
9 1     1   2412 use SWF::BinStream;
  1         4  
  1         266  
10            
11             $VERSION = '0.42';
12            
13             sub new {
14 34     34 1 58 my $class = shift;
15 34         56 my $self = [];
16            
17 34   33     132 $class=ref($class)||$class;
18            
19 34         68 bless $self, $class;
20 34         242 $self->_init;
21 34 100       77 $self->configure(@_) if @_;
22 34         86 $self;
23             }
24            
25             sub clone {
26 0     0 1 0 my $source = shift;
27 0 0       0 croak "Can't clone a class" unless ref($source);
28 0         0 my $f = 0;
29 0 0 0     0 my @attr = map {($f=($f==0)||not ref($_)) ? $_ : $_->clone} $source->configure;
  0         0  
30 0         0 $source->new(@attr);
31             }
32            
33             sub new_element {
34 0     0 1 0 my $self = shift;
35 0         0 my $name = shift;
36 0         0 my $element;
37            
38 0         0 eval {$element = $self->element_type($name)->new(@_)};
  0         0  
39 0 0       0 croak $@ if $@;
40 0         0 $element;
41             }
42            
43             sub element_type {
44 1     1   6 no strict 'refs';
  1         2  
  1         390  
45 150   66 150 0 318 return ${(ref($_[0])||$_[0]).'::_Element_Types'}{$_[1]};
  150         974  
46             }
47            
48             sub element_names {
49 1     1   6 no strict 'refs';
  1         1  
  1         458  
50 58   66 58 0 69 return @{(ref($_[0])||$_[0]).'::_Element_Names'};
  58         387  
51             }
52            
53             sub configure {
54 21     21 1 45 my ($self, @param)=@_;
55 21 100       53 @param = @{$param[0]} if (ref($param[0]) eq 'ARRAY');
  15         54  
56            
57 21 50       62 if (@param==0) {
    50          
58 0         0 my @names=$self->element_names;
59 0         0 my @result=();
60 0         0 my $key;
61 0         0 for $key (@names) {
62 0         0 push @result, $key, $self->$key();
63             }
64 0         0 return @result;
65             } elsif (@param==1) {
66 0         0 my $key = $param[0];
67 0         0 return $self->$key();
68             } else {
69 21         22 my ($key, $value);
70 21         59 while (($key, $value) = splice(@param, 0, 2)) {
71 73         236 $self->$key($value);
72             }
73 21         39 return $self;
74             }
75             }
76            
77             sub defined {
78 1     1 1 2 my $self = shift;
79 1         11 my @names=$self->element_names;
80 1         4 my $d;
81            
82 1         3 for my $key (@names) {
83 9 50       22 if ($self->element_type($key) !~ /^\$(.*)$/) {
84 0         0 $d = $self->$key->defined;
85 0 0       0 last if $d;
86             } else {
87 9         32 $d = defined $self->$key;
88 9 50       29 last if $d;
89             }
90             }
91 1         15 return $d;
92             }
93            
94             sub dumper {
95 0     0 1 0 my ($self, $outputsub, $indent)=@_;
96 0         0 my @names=$self->element_names;
97            
98 0   0     0 $indent ||= 0;
99 0   0     0 $outputsub||=\&_default_output;
100            
101 0         0 &$outputsub(ref($self)."->new(\n", 0);
102 0         0 for my $key (@names) {
103 1     1   6 no warnings 'uninitialized';
  1         2  
  1         429  
104 0 0       0 if ($self->element_type($key) =~/^\$/) {
    0          
105 0         0 my $p = $self->$key;
106 0 0       0 $p = "\"$p\"" unless $p=~/^[-\d.]+$/;
107 0 0       0 &$outputsub("$key => $p,\n", $indent+1) if defined($self->$key);
108             } elsif ($self->$key->defined) {
109 0         0 &$outputsub("$key => ", $indent+1);
110 0         0 $self->$key->dumper($outputsub, $indent+1);
111 0         0 &$outputsub(",\n", 0);
112             }
113             }
114 0         0 &$outputsub(")", $indent);
115             }
116            
117 0     0   0 sub _default_output {print ' ' x ($_[1] * 4), $_[0]};
118            
119             # _init, pack and unpack need to be overridden in the subclass.
120            
121 41     41   53 sub _init { # set attributes, parameters, etc.
122             }
123            
124             sub pack {
125 0     0 1 0 Carp::confess "Unexpected pack";
126             }
127            
128             sub unpack {
129 0     0 1 0 Carp::confess "Unexpected unpack";
130             }
131            
132             sub _create_pack {
133 37     37   56 my $classname = shift;
134 37   100     104 my $u = shift||'';
135 37         50 my $packsub = <
136             sub \{
137             my \$self = shift;
138             my \$stream = shift;
139             SUB_START
140 37         45 my $unpacksub = $packsub;
141            
142 1     1   6 no strict 'refs';
  1         2  
  1         261  
143            
144 37         64 $classname = "SWF::Element::$classname";
145 37         378 for my $key ($classname->element_names) {
146 85 100       373 if ($classname->element_type($key) !~ /^\$(.*)$/) {
147 56         95 $packsub .= "\$self->$key->pack(\$stream, \@_);";
148 56         143 $unpacksub .= "\$self->$key->unpack(\$stream, \@_);";
149             } else {
150 29         70 $packsub .= "\$stream->set_$1(\$self->$key);";
151 29         66 $unpacksub .= "\$self->$key(\$stream->get_$1);";
152             }
153             }
154 37         64 $packsub .='}';
155 37         37 $unpacksub .='}';
156 37 50   0   34 *{"${classname}::${u}pack"} = eval($packsub) unless defined &{"${classname}::${u}pack"};
  37         264  
  37         5571  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         3  
  1         3  
  1         3  
  1         4  
  1         4  
  1         38  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         2  
  1         5  
  1         5  
  1         6  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         2  
  1         6  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         2  
  1         5  
  1         4  
  1         4  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
157 37 100   0   57 *{"${classname}::${u}unpack"} = eval($unpacksub) unless defined &{"${classname}::${u}unpack"};
  36         273  
  37         8742  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         3  
  1         5  
  1         6  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         4  
  1         2  
  1         6  
  1         2  
  1         3  
  1         6  
  1         4  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         3  
  1         10  
  1         4  
  1         5  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
158             }
159            
160             # Utility sub to create subclass.
161            
162             sub _create_class {
163 1     1   5 no strict 'refs';
  1         2  
  1         695  
164            
165 163     163   243 my $classname = shift;
166 163         172 my $isa = shift;
167 163 100       337 my $base = ((@_ % 2) ? pop : 0);
168            
169 163         265 $classname = "SWF::Element::$classname";
170            
171 163         186 my $element_names = \@{"${classname}::_Element_Names"};
  163         1198  
172 163         193 my $element_types = \%{"${classname}::_Element_Types"};
  163         712  
173            
174             # $isa = [$isa] unless ref($isa) eq 'ARRAY';
175 163 100       273 @{"${classname}::ISA"}=map {$_ ? "SWF::Element::$_" : "SWF::Element"} @$isa;
  163         4311  
  193         593  
176 163         522 while (@_) {
177 396         527 my $k = shift;
178 396         1819 my $v = shift;
179 396         403 my $base1 = $base;
180 396         549 push @$element_names, $k;
181            
182 396 100       994 if ($v !~ /^\$/) {
183 213         624 my $type = $element_types->{$k} = "SWF::Element::$v";
184 213         1147 *{"${classname}::$k"} = sub {
185 45     45   104 my $self = shift;
186 45 100       103 if (@_) {
187 11         15 my $p = $_[0];
188 11 50 33     69 if (UNIVERSAL::isa($p, $type) or not defined $p) {
189 0         0 $self->[$base1] = $p;
190             } else {
191 11 50       143 $self->[$base1] = $type->new unless defined $self->[$base1];
192 11         74 $self->[$base1]->configure(@_);
193             }
194             } else {
195 34 100       202 $self->[$base1] = $type->new unless defined $self->[$base1];
196             }
197 45         568 $self->[$base1];
198 213         2212 };
199             } else {
200 183         376 $element_types->{$k} = $v;
201 183         937 *{"${classname}::$k"} = sub {
202 198     198   440 my ($self, $data) = @_;
203 198 100       499 $self->[$base1] = $data if @_>=2;
204 198         719 $self->[$base1];
205 183         679 };
206             }
207            
208 396         1157 $base++;
209            
210             }
211             }
212            
213             sub _create_flag_accessor {
214 1     1   6 no strict 'refs';
  1         2  
  1         1523  
215 104     104   170 my ($name, $flagfield, $bit, $len) = @_;
216 104         215 my $pkg = (caller)[0];
217            
218 104   100     337 $len ||=1;
219 104         173 my $field = (((1<<$len) - 1)<<$bit);
220            
221 104         826 *{"${pkg}::$name"} = sub {
222 1     1   3 my ($self, $set) = @_;
223 1   50     5 my $flags = $self->$flagfield || 0;
224            
225 1 50       5 if (defined $set) {
226 0         0 $flags &= ~$field;
227 0         0 $flags |= ($set<<$bit);
228 0         0 $self->$flagfield($flags);
229             }
230 1         6 return (($flags & $field) >> $bit);
231             }
232 104         432 }
233            
234             # Create subclasses.
235            
236             _create_class('ID', ['Scalar']);
237             _create_class('Depth', ['Scalar']);
238             _create_class('BinData', ['Scalar']);
239             _create_class('RGB', [''],
240             Red => '$UI8',
241             Green => '$UI8',
242             Blue => '$UI8');
243             _create_pack('RGB');
244             _create_class('RGBA', ['', 'RGB'],
245             Red => '$UI8',
246             Green => '$UI8',
247             Blue => '$UI8',
248             Alpha => '$UI8');
249             _create_pack('RGBA');
250             _create_class('RECT', [''],
251             Xmin => '$', Ymin => '$',
252             Xmax => '$', Ymax => '$');
253             _create_class('MATRIX', [''],
254             ScaleX => '$', ScaleY => '$',
255             RotateSkew0 => '$', RotateSkew1 => '$',
256             TranslateX => '$', TranslateY => '$');
257             _create_class('CXFORM', [''],
258             Flags => '$',
259             RedMultTerm => '$',
260             GreenMultTerm => '$',
261             BlueMultTerm => '$',
262             RedAddTerm => '$',
263             GreenAddTerm => '$',
264             BlueAddTerm => '$');
265             _create_class('CXFORMWITHALPHA', ['CXFORM'],
266             Flags => '$',
267             RedMultTerm => '$',
268             GreenMultTerm => '$',
269             BlueMultTerm => '$',
270             AlphaMultTerm => '$',
271             RedAddTerm => '$',
272             GreenAddTerm => '$',
273             BlueAddTerm => '$',
274             AlphaAddTerm => '$');
275             _create_class('STRING', ['Scalar']);
276             _create_class('PSTRING', ['STRING']);
277             _create_class('FILLSTYLE1', [''],
278             FillStyleType => '$UI8',
279             Color => 'RGB',
280             GradientMatrix => 'MATRIX',
281             Gradient => 'Array::GRADIENT1',
282             BitmapID => 'ID',
283             BitmapMatrix => 'MATRIX');
284             _create_class('FILLSTYLE3', ['FILLSTYLE1'],
285             FillStyleType => '$UI8',
286             Color => 'RGBA',
287             GradientMatrix => 'MATRIX',
288             Gradient => 'Array::GRADIENT3',
289             BitmapID => 'ID',
290             BitmapMatrix => 'MATRIX');
291             _create_class('GRADRECORD1', [''],
292             Ratio => '$UI8',
293             Color => 'RGB');
294             _create_pack('GRADRECORD1');
295             _create_class('GRADRECORD3', ['GRADRECORD1'],
296             Ratio => '$UI8',
297             Color => 'RGBA');
298             _create_class('LINESTYLE1', [''],
299             Width => '$UI16',
300             Color => 'RGB');
301             _create_pack('LINESTYLE1');
302             _create_class('LINESTYLE3', ['LINESTYLE1'],
303             Width => '$UI16',
304             Color => 'RGBA');
305             _create_class('SHAPE', [''],
306             ShapeRecords => 'Array::SHAPERECORDARRAY1');
307             _create_class('SHAPEWITHSTYLE1', ['SHAPE'],
308             FillStyles => 'Array::FILLSTYLEARRAY1',
309             LineStyles => 'Array::LINESTYLEARRAY1',
310             ShapeRecords => 'Array::SHAPERECORDARRAY1');
311             _create_class('SHAPEWITHSTYLE2', ['SHAPEWITHSTYLE1'],
312             FillStyles => 'Array::FILLSTYLEARRAY2',
313             LineStyles => 'Array::LINESTYLEARRAY2',
314             ShapeRecords => 'Array::SHAPERECORDARRAY2');
315             _create_class('SHAPEWITHSTYLE3', ['SHAPEWITHSTYLE2'],
316             FillStyles => 'Array::FILLSTYLEARRAY3',
317             LineStyles => 'Array::LINESTYLEARRAY3',
318             ShapeRecords => 'Array::SHAPERECORDARRAY3');
319             _create_class('SHAPERECORD1', ['']);
320             _create_class('SHAPERECORD2', ['SHAPERECORD1']);
321             _create_class('SHAPERECORD3', ['SHAPERECORD2']);
322             _create_class('SHAPERECORD1::STYLECHANGERECORD', ['SHAPERECORD1'],
323             MoveDeltaX => '$',
324             MoveDeltaY => '$',
325             FillStyle0 => '$',
326             FillStyle1 => '$',
327             LineStyle => '$' );
328             _create_class('SHAPERECORD2::STYLECHANGERECORD', ['SHAPERECORD1::STYLECHANGERECORD', 'SHAPERECORD2'],
329             MoveDeltaX => '$',
330             MoveDeltaY => '$',
331             FillStyle0 => '$',
332             FillStyle1 => '$',
333             LineStyle => '$',
334             FillStyles => 'Array::FILLSTYLEARRAY2',
335             LineStyles => 'Array::LINESTYLEARRAY2');
336             _create_class('SHAPERECORD3::STYLECHANGERECORD', ['SHAPERECORD2::STYLECHANGERECORD', 'SHAPERECORD3'],
337             MoveDeltaX => '$',
338             MoveDeltaY => '$',
339             FillStyle0 => '$',
340             FillStyle1 => '$',
341             LineStyle => '$',
342             FillStyles => 'Array::FILLSTYLEARRAY3',
343             LineStyles => 'Array::LINESTYLEARRAY3');
344             _create_class('SHAPERECORDn::STRAIGHTEDGERECORD', ['SHAPERECORD1', 'SHAPERECORD2', 'SHAPERECORD3'],
345             DeltaX => '$', DeltaY => '$');
346             _create_class('SHAPERECORDn::CURVEDEDGERECORD', ['SHAPERECORD1', 'SHAPERECORD2', 'SHAPERECORD3'],
347             ControlDeltaX => '$', ControlDeltaY => '$',
348             AnchorDeltaX => '$', AnchorDeltaY => '$');
349             _create_class('Tag', ['']);
350             _create_class('Tag::Identified', ['Tag']);
351             _create_class('MORPHFILLSTYLE', [''],
352             FillStyleType => '$UI8',
353             StartColor => 'RGBA',
354             EndColor => 'RGBA',
355             StartGradientMatrix => 'MATRIX',
356             EndGradientMatrix => 'MATRIX',
357             Gradient => 'Array::MORPHGRADIENT',
358             BitmapID => 'ID',
359             StartBitmapMatrix => 'MATRIX',
360             EndBitmapMatrix => 'MATRIX');
361             _create_class('MORPHGRADRECORD', [''],
362             StartRatio => '$UI8', StartColor => 'RGBA',
363             EndRatio => '$UI8', EndColor => 'RGBA');
364             _create_pack('MORPHGRADRECORD');
365             _create_class('MORPHLINESTYLE', [''],
366             StartWidth => '$UI16', EndWidth => '$UI16',
367             StartColor => 'RGBA', EndColor => 'RGBA');
368             _create_pack('MORPHLINESTYLE');
369             _create_class('BUTTONRECORD1', [''],
370             ButtonStates => '$UI8',
371             CharacterID => 'ID',
372             PlaceDepth => 'Depth',
373             PlaceMatrix => 'MATRIX');
374             _create_class('BUTTONRECORD2', ['BUTTONRECORD1'],
375             ButtonStates => '$UI8',
376             CharacterID => 'ID',
377             PlaceDepth => 'Depth',
378             PlaceMatrix => 'MATRIX',
379             ColorTransform => 'CXFORMWITHALPHA');
380             _create_class('BUTTONCONDACTION', [''],
381             Condition => '$UI16', Actions => 'Array::ACTIONRECORDARRAY');
382             _create_pack('BUTTONCONDACTION');
383             _create_class('TEXTRECORD1', [''],
384             FontID => 'ID',
385             TextColor => 'RGB',
386             XOffset => '$SI16',
387             YOffset => '$SI16',
388             TextHeight => '$UI16',
389             GlyphEntries => 'Array::GLYPHENTRYARRAY');
390             _create_class('TEXTRECORD2', ['TEXTRECORD1'],
391             FontID => 'ID',
392             TextColor => 'RGBA',
393             XOffset => '$SI16',
394             YOffset => '$SI16',
395             TextHeight => '$UI16',
396             GlyphEntries => 'Array::GLYPHENTRYARRAY');
397             _create_class('TEXTRECORD::TYPE0', ['','TEXTRECORD1','TEXTRECORD2'],
398             GlyphEntries => 'Array::GLYPHENTRYARRAY');
399             _create_pack('TEXTRECORD::TYPE0');
400             _create_class('GLYPHENTRY', [''],
401             GlyphIndex => '$', GlyphAdvance => '$');
402             _create_class('TEXTRECORD1::TYPE1', ['TEXTRECORD1'],
403             FontID => 'ID',
404             TextColor => 'RGB',
405             XOffset => '$SI16',
406             YOffset => '$SI16',
407             TextHeight => '$UI16');
408             _create_class('TEXTRECORD2::TYPE1', ['TEXTRECORD1::TYPE1', 'TEXTRECORD2'],
409             FontID => 'ID',
410             TextColor => 'RGBA',
411             XOffset => '$SI16',
412             YOffset => '$SI16',
413             TextHeight => '$UI16');
414             _create_class('SOUNDINFO', [''],
415             SyncFlags => '$',
416             InPoint => '$UI32',
417             OutPoint => '$UI32',
418             LoopCount => '$UI16',
419             EnvelopeRecords => 'Array::SOUNDENVELOPEARRAY');
420             _create_class('SOUNDENVELOPE', [''],
421             Pos44 => '$UI32', LeftLevel => '$UI16', RightLevel => '$UI16');
422             _create_pack('SOUNDENVELOPE');
423             _create_class('ACTIONTagNumber', ['Scalar']);
424             _create_class('ACTIONRECORD', [''],
425             Tag => 'ACTIONTagNumber',
426             LocalLabel => '$');
427             _create_class('ACTIONDATA', ['Scalar']);
428             _create_class('ACTIONDATA::String', ['ACTIONDATA']);
429             _create_class('ACTIONDATA::Property', ['ACTIONDATA']);
430             _create_class('ACTIONDATA::NULL', ['ACTIONDATA']);
431             _create_class('ACTIONDATA::UNDEF', ['ACTIONDATA']);
432             _create_class('ACTIONDATA::Register', ['ACTIONDATA']);
433             _create_class('ACTIONDATA::Boolean', ['ACTIONDATA']);
434             _create_class('ACTIONDATA::Double', ['ACTIONDATA']);
435             _create_class('ACTIONDATA::Integer', ['ACTIONDATA']);
436             _create_class('ACTIONDATA::Lookup', ['ACTIONDATA']);
437             _create_class('CLIPACTIONRECORD', [''],
438             EventFlags => '$',
439             KeyCode => '$UI8',
440             Actions => 'Array::ACTIONRECORDARRAY');
441             _create_class('ASSET', [''],
442             ID => 'ID',
443             Name => 'STRING');
444             _create_pack('ASSET');
445             _create_class('REGISTERPARAM', [''],
446             Register => '$UI8',
447             ParamName => 'STRING');
448             _create_pack('REGISTERPARAM');
449            
450             ##########
451            
452             package SWF::Element::Scalar;
453            
454             use overload
455 0         0 '""' => \&value,
456             '0+' => \&value,
457 0     0   0 '++' => sub {${$_[0]}++},
458 0     0   0 '--' => sub {${$_[0]}--},
  0         0  
459 1         17 '=' => \&clone,
460             fallback =>1,
461 1     1   8 ;
  1         3  
462             @SWF::Element::Scalar::ISA = ('SWF::Element');
463            
464             sub new {
465 10     10   18 my $class = shift;
466 10         15 my ($self, $data);
467            
468 10         15 $self = \$data;
469 10   33     57 bless $self, ref($class)||$class;
470 10         41 $self->_init;
471 10 50       28 $self->configure(@_) if @_;
472 10         31 $self;
473             }
474            
475             sub clone {
476 0     0   0 my $self = shift;
477 0 0       0 Carp::croak "Can't clone a class" unless ref($self);
478 0         0 my $new = $self->new($self->value);
479             }
480            
481             sub configure {
482 8     8   61 my ($self, $newval)=@_;
483             # Carp::croak "Can't set $newval in ".ref($self) unless $newval=~/^[\d.]*$/;
484 8 50       23 unless (ref($newval)) {
  0 0       0  
485 8         309 $$self = $newval;
486             } elsif (eval{$newval->isa('SWF::Element::Scalar')}) {
487 0         0 $$self = $newval->value;
488             }
489 8         39 $self;
490             }
491             sub value {
492 6     6   10 ${$_[0]};
  6         36  
493             }
494            
495             sub defined {
496 3     3   3 defined ${$_[0]};
  3         19  
497             }
498            
499             # 'pack' and 'unpack' should be overridden in the subclass or
500             # the owner class is responsible for packing/unpacking THIS.
501            
502             sub pack {
503 0     0   0 Carp::croak "'pack' should be overridden in ".ref($_[0]);
504             }
505            
506             sub unpack {
507 0     0   0 Carp::croak "'unpack' should be overridden in ".ref($_[0]);
508             }
509            
510             sub dumper {
511 0     0   0 my ($self, $outputsub)=@_;
512            
513 0   0     0 $outputsub||=\&SWF::Element::_default_output;
514            
515 0         0 &$outputsub($self->value, 0);
516             }
517            
518 10     10   22 sub _init {}
519            
520            
521             ##########
522            
523             package SWF::Element::ID;
524            
525             sub pack {
526 2     2   6 my ($self, $stream) = @_;
527            
528 2         10 $stream->set_UI16($self->value);
529             }
530            
531             sub unpack {
532 2     2   4 my ($self, $stream) = @_;
533            
534 2         10 $self->configure($stream->get_UI16);
535             }
536            
537             ##########
538            
539             package SWF::Element::Depth;
540            
541             sub pack {
542 1     1   2 my ($self, $stream) = @_;
543            
544 1         6 $stream->set_UI16($self->value);
545             }
546            
547             sub unpack {
548 1     1   2 my ($self, $stream) = @_;
549            
550 1         6 $self->configure($stream->get_UI16);
551             }
552            
553             ##########
554            
555             package SWF::Element::Array;
556            
557             sub new {
558 9     9   13 my $class = shift;
559 9         19 my $self = [];
560            
561 9   33     67 bless $self, ref($class)||$class;
562 9         46 $self->_init;
563 9 50       26 $self->configure(@_) if @_;
564            
565 9         34 $self;
566             }
567            
568             sub configure {
569 2     2   5 my ($self, @param)=@_;
570 2 50 33     15 @param = @{$param[0]} if (ref($param[0]) eq 'ARRAY' and ref($param[0][0]));
  2         7  
571 2         5 for my $p (@param) {
572 10         23 my $element = $self->new_element;
573 10 50 33     72 if (UNIVERSAL::isa($p, ref($element)) or not defined $p) {
    50          
574 0         0 $element = $p;
575             } elsif (ref($p) eq 'ARRAY') {
576 10         26 $element->configure($p);
577             } else {
578             # Carp::croak "Element type mismatch: ".ref($p)." in ".ref($self);
579 0         0 Carp::confess "Element type mismatch: ".ref($p)." in ".ref($self);
580             }
581 10         26 push @$self, $element;
582             }
583 2         7 $self;
584             }
585            
586             sub clone {
587 0     0   0 my $self = $_[0];
588 0 0       0 die "Can't clone a class" unless ref($self);
589 0         0 my $new = $self->new;
590 0         0 for my $i (@$self) {
591 0         0 push @$new, $i->clone;
592             }
593 0         0 $new;
594             }
595            
596             sub pack {
597 1     1   2 my $self = shift;
598            
599 1         3 for my $element (@$self) {
600 9         105 $element->pack(@_);
601             }
602 1         25 $self->last(@_);
603             }
604            
605             sub unpack {
606 1     1   2 my $self = shift;
607             {
608 1         2 my $element = $self->new_element;
  10         24  
609 10         30 $element->unpack(@_);
610 10 100       35 last if $self->is_last($element);
611 9         17 push @$self, $element;
612 9         14 redo;
613             }
614             }
615            
616             sub defined {
617 1     1   3 return @{shift()} > 0;
  1         4  
618             }
619            
620             sub dumper {
621 0     0   0 my ($self, $outputsub, $indent) = @_;
622            
623 0   0     0 $indent ||= 0;
624 0   0     0 $outputsub||=\&SWF::Element::_default_output;
625            
626 0         0 &$outputsub(ref($self)."->new([\n", 0);
627 0         0 my $n = 0;
628 0         0 for my $i (@$self) {
629 0         0 &$outputsub('', $indent+1);
630 0         0 $i->dumper($outputsub, $indent+1);
631 0         0 &$outputsub(",\t\t\t# $n\n", 0);
632 0         0 $n++;
633             }
634 0         0 &$outputsub("])", $indent);
635             }
636            
637             sub _init {
638 9     9   13 my $self = shift;
639            
640 9         56 for my $element (@$self) {
641 0 0 0     0 last unless ref($element) eq '' or ref($element) eq 'ARRAY';
642 0         0 my $new = $self->new_element;
643 0 0       0 last unless ref($new);
644 0         0 $new->configure($element);
645 0         0 $element = $new;
646             }
647             }
648            
649 0     0   0 sub new_element {}
650 0     0   0 sub is_last {0}
651 0     0   0 sub last {};
652            
653             sub _create_array_class {
654 1     1   1775 no strict 'refs';
  1         1  
  1         1173  
655 33     33   74 my ($classname, $isa, $newelement, $last, $is_last)=@_;
656            
657 33         63 $classname = "Array::$classname";
658 33         65 SWF::Element::_create_class($classname, $isa);
659            
660 33         72 $classname = "SWF::Element::$classname";
661 33 100       76 if ($newelement) {
662 31         52 $newelement = "SWF::Element::$newelement";
663 31     21   120 *{"${classname}::new_element"} = sub {shift; $newelement->new(@_)};
  31         158  
  21         91  
  21         81  
664             }
665 33 100       76 *{"${classname}::last"} = $last if $last;
  9         42  
666 33 100       77 *{"${classname}::is_last"} = $is_last if $is_last;
  6         44  
667             }
668            
669             _create_array_class('FILLSTYLEARRAY1', ['Array1'], 'FILLSTYLE1');
670             _create_array_class('FILLSTYLEARRAY2', ['Array2', 'Array::FILLSTYLEARRAY1'], 'FILLSTYLE1');
671             _create_array_class('FILLSTYLEARRAY3', ['Array::FILLSTYLEARRAY2'],'FILLSTYLE3');
672             _create_array_class('GRADIENT1', ['Array1'], 'GRADRECORD1');
673             _create_array_class('GRADIENT3', ['Array::GRADIENT1'], 'GRADRECORD3');
674             _create_array_class('LINESTYLEARRAY1', ['Array1'], 'LINESTYLE1');
675             _create_array_class('LINESTYLEARRAY2', ['Array2', 'Array::LINESTYLEARRAY1'], 'LINESTYLE1');
676             _create_array_class('LINESTYLEARRAY3', ['Array::LINESTYLEARRAY2'], 'LINESTYLE3');
677 1     1   6 _create_array_class('SHAPERECORDARRAY1', ['Array'], 'SHAPERECORD1',
678             sub {$_[1]->set_bits(0,6)},
679 10     10   105 sub {$_[1]->isa('SWF::Element::SHAPERECORDn::ENDSHAPERECORD')});
680            
681             _create_array_class('SHAPERECORDARRAY2', ['Array::SHAPERECORDARRAY1'], 'SHAPERECORD2');
682             _create_array_class('SHAPERECORDARRAY3', ['Array::SHAPERECORDARRAY2'], 'SHAPERECORD3');
683             _create_array_class('MORPHFILLSTYLEARRAY', ['Array2'], 'MORPHFILLSTYLE');
684             _create_array_class('MORPHLINESTYLEARRAY', ['Array2'], 'MORPHLINESTYLE');
685             _create_array_class('MORPHGRADIENT', ['Array1'], 'MORPHGRADRECORD');
686 0     0   0 _create_array_class('BUTTONRECORDARRAY1', ['Array'], 'BUTTONRECORD1',
687             sub {$_[1]->set_UI8(0)},
688 0     0   0 sub {$_[1]->ButtonStates == 0});
689            
690             _create_array_class('BUTTONRECORDARRAY2', ['Array::BUTTONRECORDARRAY1'], 'BUTTONRECORD2');
691             _create_array_class('BUTTONCONDACTIONARRAY', ['Array'], 'BUTTONCONDACTION');
692             _create_array_class('GLYPHSHAPEARRAY1', ['Array'], 'SHAPE');
693             _create_array_class('GLYPHSHAPEARRAY2', ['Array'], 'SHAPE');
694             _create_array_class('CODETABLE', ['Array::Scalar']);
695             _create_array_class('FONTADVANCETABLE', ['Array::Scalar']);
696 0     0   0 _create_array_class('FONTBOUNDSTABLE', ['Array'], 'RECT', sub {});
697 0     0   0 _create_array_class('TEXTRECORDARRAY1', ['Array'], 'TEXTRECORD1',
698             sub {$_[1]->set_UI8(0)},
699 0     0   0 sub {$_[1]->isa('SWF::Element::TEXTRECORD::End')});
700            
701             _create_array_class('TEXTRECORDARRAY2', ['Array::TEXTRECORDARRAY1'], 'TEXTRECORD2');
702             _create_array_class('GLYPHENTRYARRAY', ['Array1'], 'GLYPHENTRY');
703             _create_array_class('SOUNDENVELOPEARRAY', ['Array1'], 'SOUNDENVELOPE');
704 0     0   0 _create_array_class('ACTIONRECORDARRAY', ['Array'], 'ACTIONRECORD',
705             sub {$_[1]->set_UI8(0)},
706 0     0   0 sub {$_[1]->Tag == 0});
707             _create_array_class('ACTIONDATAARRAY', ['Array'], 'ACTIONDATA',
708 0     0   0 sub {});
709             _create_array_class('STRINGARRAY', ['Array3'], 'STRING');
710 0     0   0 _create_array_class('CLIPACTIONRECORDARRAY', ['Array'], 'CLIPACTIONRECORD',
711             sub {$_[1]->set_UI32(0)},
712 0     0   0 sub {$_[1]->EventFlags == 0});
713             _create_array_class('ASSETARRAY', ['Array3'], 'ASSET');
714             _create_array_class('TAGARRAY', ['Array'], 'Tag',
715 0     0   0 sub {},
716 0 0   0   0 sub {$_[1]->tag_name eq 'End' && ((push @{$_[0]}, $_[1]),1)});
  0         0  
717             _create_array_class('REGISTERPARAMARRAY', ['Array'], 'REGISTERPARAM',
718 0     0   0 sub {});
719            
720             ##########
721            
722             package SWF::Element::Array::Scalar;
723            
724             @SWF::Element::Array::Scalar::ISA=qw(SWF::Element::Array);
725            
726             sub configure {
727 0     0   0 my $self = shift;
728            
729 0 0       0 if (ref($_[0]) eq 'ARRAY') {
730 0         0 push @$self, @{$_[0]};
  0         0  
731             } else {
732 0         0 push @$self, @_;
733             }
734 0         0 $self;
735             }
736            
737             sub clone {
738 0     0   0 my $self = $_[0];
739 0 0       0 die "Can't clone a class" unless ref($self);
740 0         0 $self->new(@$self);
741             }
742            
743             sub dumper {
744 0     0   0 my ($self, $outputsub, $indent) = @_;
745 0         0 my @data;
746            
747 0         0 &$outputsub(ref($self)."->new([\n", 0);
748 0         0 for (my $i = 0; $i < @$self; $i+=8) {
749 0 0       0 my @data = @$self[$i..($i+7 > $#$self ? $#$self : $i+7)];
750 0         0 &$outputsub(sprintf("%5d,"x@data."\n", @data), 0);
751             }
752 0         0 &$outputsub("])", $indent);
753             }
754            
755             ##########
756            
757             package SWF::Element::Array1;
758 1     1   7 use vars qw(@ISA);
  1         2  
  1         265  
759            
760             @ISA=qw(SWF::Element::Array);
761            
762             sub pack {
763 0     0   0 my $self = shift;
764 0         0 my $count = @$self;
765            
766 0         0 $_[0]->set_UI8($count);
767 0         0 $self->_pack(@_);
768             }
769            
770             sub _pack {
771 2     2   9 my $self = shift;
772            
773 2         6 for my $element (@$self) {
774 1         297 $element->pack(@_);
775             }
776             }
777            
778            
779             sub unpack {
780 0     0   0 my $self = shift;
781            
782 0         0 $self->_unpack($_[0]->get_UI8, @_);
783             }
784            
785             sub _unpack {
786 2     2   5 my $self = shift;
787 2         3 my $count = shift;
788            
789 2         8 while (--$count>=0) {
790 1         5 my $element = $self->new_element;
791 1         13 $element->unpack(@_);
792 1         6 push @$self, $element;
793             }
794             }
795            
796             ##########
797            
798             package SWF::Element::Array2;
799 1     1   7 use vars qw(@ISA);
  1         2  
  1         202  
800            
801             @ISA=qw(SWF::Element::Array1);
802            
803             sub pack {
804 2     2   3 my $self=shift;
805 2         4 my $stream=$_[0];
806 2         3 my $count=@$self;
807            
808 2 50       5 if ($count>254) {
809 0         0 $stream->set_UI8(0xFF);
810 0         0 $stream->set_UI16($count);
811             } else {
812 2         6 $stream->set_UI8($count);
813             }
814 2         17 $self->_pack(@_);
815             }
816            
817             sub unpack {
818 2     2   6 my $self=shift;
819 2         4 my $stream=$_[0];
820 2         7 my $count=$stream->get_UI8;
821            
822 2 50       35 $count=$stream->get_UI16 if $count==0xFF;
823            
824 2         27 $self->_unpack($count, @_);
825             }
826            
827             ##########
828            
829             package SWF::Element::Array3;
830 1     1   5 use vars qw(@ISA);
  1         2  
  1         1922  
831            
832             @ISA=qw(SWF::Element::Array1);
833            
834             sub unpack {
835 0     0   0 my $self = shift;
836            
837 0         0 $self->_unpack($_[0]->get_UI16, @_);
838             }
839            
840             sub pack {
841 0     0   0 my $self = shift;
842            
843 0         0 $_[0]->set_UI16(scalar @$self);
844 0         0 $self->_pack(@_);
845             }
846            
847             ##########
848            
849             package SWF::Element::Array::STRINGARRAY;
850            
851             sub configure {
852 0     0   0 my ($self, @param)=@_;
853 0 0       0 @param = @{$param[0]} if (ref($param[0]) eq 'ARRAY');
  0         0  
854 0         0 for my $p (@param) {
855 0         0 my $element = $self->new_element;
856 0 0 0     0 if (UNIVERSAL::isa($p, ref($element)) or not defined $p) {
    0          
857 0         0 $element = $p;
858             } elsif (ref($p) eq '') {
859 0         0 $element->configure($p);
860             } else {
861 0         0 Carp::croak "Element type mismatch: ".ref($p)." in ".ref($self);
862             }
863 0         0 push @$self, $element;
864             }
865 0         0 $self;
866             }
867            
868             ##########
869            
870             package SWF::Element::RECT;
871            
872             sub pack {
873 2     2   5 my ($self, $stream)=@_;
874 2         6 $stream->flush_bits;
875 2         6 $stream->set_sbits_list(5, $self->Xmin, $self->Xmax, $self->Ymin, $self->Ymax);
876             }
877            
878             sub unpack {
879 1     1   3 my ($self, $stream)=@_;
880 1         3 $stream->flush_bits;
881 1         4 my $nbits=$stream->get_bits(5);
882            
883 1         4 for my $i(qw/Xmin Xmax Ymin Ymax/) {
884 4         13 $self->$i($stream->get_sbits($nbits));
885             }
886             }
887            
888             ##########
889            
890             package SWF::Element::MATRIX;
891            
892             sub _init {
893 2     2   5 my $self = shift;
894 2         8 $self->ScaleX(1);
895 2         7 $self->ScaleY(1);
896 2         8 $self->RotateSkew0(0);
897 2         8 $self->RotateSkew1(0);
898             }
899            
900             sub pack {
901 1     1   2 my ($self, $stream)=@_;
902            
903 1         5 $stream->flush_bits;
904 1 50 33     3 if ($self->ScaleX != 1 or $self->ScaleY != 1) {
905 0         0 $stream->set_bits(1,1);
906 0         0 $stream->set_sbits_list(5, $self->ScaleX * 65536, $self->ScaleY * 65536);
907             } else {
908 1         5 $stream->set_bits(0,1);
909             }
910 1 50 33     5 if ($self->RotateSkew0 != 0 or $self->RotateSkew1 != 0) {
911 0         0 $stream->set_bits(1,1);
912 0         0 $stream->set_sbits_list(5, $self->RotateSkew0 * 65536, $self->RotateSkew1 * 65536);
913             } else {
914 1         10 $stream->set_bits(0,1);
915             }
916 1         4 $stream->set_sbits_list(5, $self->TranslateX, $self->TranslateY);
917             }
918            
919             sub unpack {
920 1     1   16 my ($self, $stream)=@_;
921 1         2 my ($hasscale, $hasrotate);
922            
923 1         5 $stream->flush_bits;
924 1 50       5 if ($hasscale = $stream->get_bits(1)) {
925 0         0 my $nbits=$stream->get_bits(5);
926             # $nbits = 32 if $nbits == 0; # ???
927 0         0 $self->ScaleX($stream->get_sbits($nbits) / 65536);
928 0         0 $self->ScaleY($stream->get_sbits($nbits) / 65536);
929             } else {
930 1         4 $self->ScaleX(1);
931 1         4 $self->ScaleY(1);
932             }
933 1 50       4 if ($hasrotate = $stream->get_bits(1)) {
934 0         0 my $nbits=$stream->get_bits(5);
935             # $nbits = 32 if $nbits == 0; # ???
936 0         0 $self->RotateSkew0($stream->get_sbits($nbits) / 65536);
937 0         0 $self->RotateSkew1($stream->get_sbits($nbits) / 65536);
938             } else {
939 1         4 $self->RotateSkew0(0);
940 1         3 $self->RotateSkew1(0);
941             }
942 1         22 my $nbits=$stream->get_bits(5);
943             # my $scalex = $self->ScaleX;
944             # $nbits = 32 if $nbits == 0 and ($scalex == 0 or $scalex >= 16383.99998474 or $scalex <= -16383.99998474); # ???
945 1         7 $self->TranslateX($stream->get_sbits($nbits));
946 1         4 $self->TranslateY($stream->get_sbits($nbits));
947             }
948            
949             sub defined {
950 1     1   2 my $self = shift;
951            
952 1   0     4 return (defined($self->TranslateX) or defined($self->TranslateY) or
953             $self->ScaleX != 1 or $self->ScaleY != 1 or
954             $self->RotateSkew0 != 0 or $self->RotateSkew1 != 0);
955             }
956            
957             sub scale {
958 0     0   0 my ($self, $xscale, $yscale)=@_;
959 0 0       0 $yscale=$xscale unless defined $yscale;
960            
961 0         0 $self->ScaleX($self->ScaleX * $xscale);
962 0         0 $self->RotateSkew0($self->RotateSkew0 * $xscale);
963 0         0 $self->ScaleY($self->ScaleY * $yscale);
964 0         0 $self->RotateSkew1($self->RotateSkew1 * $yscale);
965 0         0 $self;
966             }
967            
968             sub moveto {
969 0     0   0 my ($self, $x, $y)=@_;
970 0         0 $self->TranslateX($x);
971 0         0 $self->TranslateY($y);
972 0         0 $self;
973             }
974            
975             sub rotate {
976 0     0   0 my ($self, $degree)=@_;
977 0         0 $degree = $degree*3.14159265358979/180;
978 0         0 my $sin = sin($degree);
979 0         0 my $cos = cos($degree);
980 0         0 my $a = $self->ScaleX;
981 0         0 my $b = $self->RotateSkew0;
982 0         0 my $c = $self->RotateSkew1;
983 0         0 my $d = $self->ScaleY;
984 0         0 $self->ScaleX($a*$cos-$b*$sin);
985 0         0 $self->RotateSkew0($a*$sin+$b*$cos);
986 0         0 $self->RotateSkew1($c*$cos-$d*$sin);
987 0         0 $self->ScaleY($c*$sin+$d*$cos);
988            
989 0         0 $self;
990             }
991            
992             ##########
993            
994             package SWF::Element::CXFORM;
995            
996             sub pack {
997 0     0   0 my ($self, $stream)=@_;
998 0         0 my @param = map $self->$_, $self->element_names;
999 0         0 shift @param;
1000 0         0 my $half = @param>>1;
1001 0         0 my @mult = @param[0..$half-1];
1002 0         0 my @add = @param[$half..$#param];
1003            
1004 0         0 $stream->flush_bits;
1005 0 0       0 if (grep defined $_, @add) {
1006 0         0 $stream->set_bits(1,1);
1007             } else {
1008 0         0 $stream->set_bits(0,1);
1009 0         0 @add = ();
1010             }
1011 0 0       0 if (grep defined $_, @mult) {
1012 0         0 $stream->set_bits(1,1);
1013             } else {
1014 0         0 $stream->set_bits(0,1);
1015 0         0 @mult = ();
1016             }
1017 0 0 0     0 $stream->set_sbits_list(4, @mult, @add) if @add or @mult;
1018             }
1019            
1020             sub unpack {
1021 0     0   0 my ($self, $stream)=@_;
1022            
1023 0         0 $stream->flush_bits;
1024 0         0 my $hasAdd = $stream->get_bits(1);
1025 0         0 my $hasMult = $stream->get_bits(1);
1026            
1027 0         0 $self->Flags($hasAdd | ($hasMult<<1));
1028            
1029 0         0 my $nbits = $stream->get_bits(4);
1030 0         0 my @names = $self->element_names;
1031 0         0 shift @names;
1032 0         0 my $half = @names>>1;
1033            
1034 0 0       0 if ($hasMult) {
1035 0         0 for my $i (@names[0..$half-1]) {
1036 0         0 $self->$i($stream->get_sbits($nbits));
1037             }
1038             }
1039 0 0       0 if ($hasAdd) {
1040 0         0 for my $i (@names[$half..$#names]) {
1041 0         0 $self->$i($stream->get_sbits($nbits));
1042             }
1043             }
1044             }
1045            
1046             SWF::Element::_create_flag_accessor('HasAddTerms', 'Flags', 0);
1047             SWF::Element::_create_flag_accessor('HasMultTerms', 'Flags', 1);
1048            
1049             ##########
1050            
1051             package SWF::Element::BinData;
1052            
1053 1     1   8 use Data::TemporaryBag;
  1         3  
  1         259  
1054            
1055             sub _init {
1056 0     0   0 my $self = shift;
1057            
1058 0         0 $$self = Data::TemporaryBag->new;
1059             }
1060            
1061             sub configure {
1062 0     0   0 my ($self, $newval) = @_;
1063            
1064 0 0       0 if (ref($newval)) {
1065 0 0       0 if ($newval->isa('Data::TemporaryBag')) {
    0          
1066 0         0 $$self = $newval->clone;
1067             } elsif ($newval->isa('SWF::Element::BinData')) {
1068 0         0 $self = $newval->clone;
1069             } else {
1070 0         0 Carp::croak "Can't set ".ref($newval)." in ".ref($self);
1071             }
1072             } else {
1073 0 0       0 $$self = Data::TemporaryBag->new($newval) if defined $newval;
1074             }
1075 0         0 $self;
1076             }
1077            
1078             sub clone {
1079 0     0   0 my $self = shift;
1080            
1081 0         0 $self->new($$self);
1082             }
1083            
1084             for my $sub (qw/substr value defined/) {
1085 1     1   6 no strict 'refs';
  1         2  
  1         357  
1086             *{"SWF::Element::BinData::$sub"} = sub {
1087 0     0   0 my $self=shift;
1088 0         0 $$self->$sub(@_);
1089             };
1090             }
1091            
1092             sub add {
1093 0     0   0 my $self = shift;
1094            
1095 0         0 $$self->add(@_);
1096 0         0 $self;
1097             }
1098            
1099             sub Length {
1100 0     0   0 $ {$_[0]}->length;
  0         0  
1101             }
1102            
1103             sub pack {
1104 0     0   0 my ($self, $stream)=@_;
1105 0         0 my $size = $self->Length;
1106 0         0 my $pos = 0;
1107            
1108 0         0 while ($size > $pos) {
1109 0         0 $stream->set_string($self->substr($pos, 1024));
1110 0         0 $pos += 1024;
1111             }
1112             }
1113            
1114             sub unpack {
1115 0     0   0 my ($self, $stream, $len)=@_;
1116            
1117 0         0 while ($len > 0) {
1118 0 0       0 my $size = ($len > 1024) ? 1024 : $len;
1119 0         0 $self->add($stream->get_string($size));
1120 0         0 $len -= $size;
1121             }
1122             }
1123            
1124             sub save {
1125 0     0   0 my ($self, $file) = @_;
1126 1     1   8 no strict 'refs'; # so that a symbol ref as $file works
  1         2  
  1         323  
1127 0         0 local(*F);
1128 0 0 0     0 unless (ref($file) or $file =~ /^\*[\w:]+$/) {
1129             # Assume $file is a filename
1130 0 0       0 open(F, "> $file") or die "Can't open $file: $!";
1131 0         0 $file = *F;
1132             }
1133 0         0 binmode($file);
1134 0         0 my $stream = SWF::BinStream::Write->new;
1135 0     0   0 $stream->autoflush(1000, sub {print $file $_[1]});
  0         0  
1136 0         0 $self->pack($stream);
1137 0         0 print $file $stream->flush_stream;
1138 0         0 close $file;
1139             }
1140            
1141             sub load {
1142 0     0   0 my($self, $file) = @_;
1143 1     1   6 no strict 'refs'; # so that a symbol ref as $file works
  1         2  
  1         14008  
1144 0         0 local(*F);
1145 0 0 0     0 unless (ref($file) or $file =~ /^\*[\w:]+$/) {
1146             # Assume $file is a filename
1147 0 0       0 open(F, $file) or die "Can't open $file: $!";
1148 0         0 $file = *F;
1149             }
1150 0         0 binmode($file);
1151 0         0 my $size = (stat $file)[7];
1152 0     0   0 my $stream = SWF::BinStream::Read->new('', sub {my $data; read $file, $data, 1000; $_[0]->add_stream($data)});
  0         0  
  0         0  
  0         0  
1153 0         0 $self->unpack($stream, $size);
1154 0         0 close $file;
1155             }
1156            
1157             {
1158             my $label = 'A';
1159            
1160             sub dumper {
1161 0     0   0 my ($self, $outputsub, $indent) = @_;
1162            
1163 0   0     0 $indent ||= 0;
1164 0   0     0 $outputsub||=\&SWF::Element::_default_output;
1165            
1166 0         0 &$outputsub(ref($self)."->new\n", 0);
1167            
1168 0         0 my $size = $self->Length;
1169 0         0 my $pos = 0;
1170            
1171 0         0 while ($size > $pos) {
1172 0         0 my $data = CORE::pack('u', $self->substr($pos, 1024));
1173 0         0 &$outputsub("->add(unpack('u', <<'$label'))\n$data$label\n", $indent+1);
1174 0         0 $pos += 1024;
1175 0         0 $label++;
1176             }
1177             }
1178             }
1179            
1180             ##########
1181            
1182             package SWF::Element::STRING;
1183            
1184             sub pack {
1185 1     1   3 my ($self, $stream)=@_;
1186 1         7 $stream->set_string($self->value."\0");
1187             }
1188            
1189             sub unpack {
1190 1     1   3 my ($self, $stream)=@_;
1191 1         3 my $str='';
1192 1         3 my $char;
1193 1         13 $str.=$char while (($char = $stream->get_string(1)) ne "\0");
1194 1         21 $self->configure($str);
1195             }
1196            
1197             sub dumper {
1198 0     0   0 my ($self, $outputsub)=@_;
1199 0         0 my $data = $self->value;
1200            
1201 0         0 $data =~ s/([\\\$\@\"])/\\$1/gs;
1202 0         0 $data =~ s/([\x00-\x1F\x80-\xFF])/sprintf('\\x%.2X', ord($1))/ges;
  0         0  
1203 0   0     0 $outputsub||=\&SWF::Element::_default_output;
1204            
1205 0         0 &$outputsub("\"$data\"", 0);
1206             }
1207            
1208             ##########
1209            
1210             package SWF::Element::PSTRING;
1211            
1212             sub pack {
1213 0     0   0 my ($self, $stream)=@_;
1214 0         0 my $str = $self->value;
1215            
1216 0         0 $stream->set_UI8(length($str));
1217 0         0 $stream->set_string($str);
1218             }
1219            
1220             sub unpack {
1221 0     0   0 my ($self, $stream)=@_;
1222 0         0 my $len = $stream->get_UI8;
1223            
1224 0         0 $self->configure($stream->get_string($len));
1225             }
1226            
1227             ##########
1228            
1229             package SWF::Element::FILLSTYLE1;
1230            
1231             sub pack {
1232 1     1   3 my ($self, $stream)=@_;
1233 1         3 my $style=$self->FillStyleType;
1234 1         5 $stream->set_UI8($style);
1235 1 50 0     4 if ($style==0x00) {
    0 0        
    0          
1236 1         3 $self->Color->pack($stream);
1237             } elsif ($style==0x10 or $style==0x12) {
1238 0         0 $self->GradientMatrix->pack($stream);
1239 0         0 $self->Gradient->pack($stream);
1240             } elsif ($style>=0x40 or $style<=0x43) {
1241 0         0 $self->BitmapID->pack($stream);
1242 0         0 $self->BitmapMatrix->pack($stream);
1243             }
1244             }
1245            
1246             sub unpack {
1247 1     1   2 my ($self, $stream)=@_;
1248 1         5 my $style = $self->FillStyleType($stream->get_UI8);
1249 1 50 0     5 if ($style==0x00) {
    0 0        
    0          
1250 1         5 $self->Color->unpack($stream);
1251             } elsif ($style==0x10 or $style==0x12) {
1252 0         0 $self->GradientMatrix->unpack($stream);
1253 0         0 $self->Gradient->unpack($stream);
1254             } elsif ($style>=0x40 or $style<=0x43) {
1255 0         0 $self->BitmapID->unpack($stream);
1256 0         0 $self->BitmapMatrix->unpack($stream);
1257             }
1258             }
1259            
1260             ##########
1261            
1262             package SWF::Element::SHAPE;
1263            
1264             sub pack {
1265 0     0   0 my ($self, $stream, $nfillbits, $nlinebits)=@_;
1266             # my ($fillidx, $lineidx)=(-1,-1);
1267            
1268 0         0 $stream->flush_bits;
1269            
1270             =begin possible_unnecessary
1271            
1272             for my $shaperec (@{$self->ShapeRecords}) {
1273             next unless $shaperec->isa('SWF::Element::SHAPERECORD1::STYLECHANGERECORD');
1274             my $style;
1275             $style = $shaperec->FillStyle0;
1276             $fillidx = $style if (defined $style and $fillidx < $style);
1277             $style = $shaperec->FillStyle1;
1278             $fillidx = $style if (defined $style and $fillidx < $style);
1279             $style = $shaperec->LineStyle;
1280             $lineidx = $style if (defined $style and $lineidx < $style);
1281             }
1282             if ($fillidx>=0) {
1283             $nfillbits=1;
1284             $nfillbits++ while ($fillidx>=(1<<$nfillbits));
1285             } else {
1286             $nfillbits=0;
1287             }
1288             if ($lineidx>=0) {
1289             $nlinebits=1;
1290             $nlinebits++ while ($lineidx>=(1<<$nlinebits));
1291             } else {
1292             $nlinebits=0;
1293             }
1294            
1295             =end possible_unnecessary
1296            
1297             =cut
1298            
1299 0         0 $stream->set_bits($nfillbits, 4);
1300 0         0 $stream->set_bits($nlinebits, 4);
1301            
1302 0         0 $self->ShapeRecords->pack($stream, \$nfillbits, \$nlinebits);
1303             }
1304            
1305             sub unpack {
1306 1     1   3 my ($self, $stream)=@_;
1307 1         2 my ($nfillbits, $nlinebits);
1308            
1309 1         5 $stream->flush_bits;
1310 1         4 $nfillbits=$stream->get_bits(4);
1311 1         5 $nlinebits=$stream->get_bits(4);
1312            
1313 1         7 $self->ShapeRecords->unpack($stream, \$nfillbits, \$nlinebits);
1314             }
1315            
1316             ##########
1317            
1318             package SWF::Element::SHAPEWITHSTYLE1;
1319            
1320             sub pack {
1321 1     1   2 my ($self, $stream)=@_;
1322 1         2 my ($fillidx, $lineidx)=($#{$self->FillStyles}+1, $#{$self->LineStyles}+1);
  1         3  
  1         4  
1323 1         2 my ($nfillbits, $nlinebits)=(0,0);
1324            
1325 1         3 $self->FillStyles->pack($stream);
1326 1         4 $self->LineStyles->pack($stream);
1327            
1328 1 50       4 if ($fillidx>0) {
1329 1         2 $nfillbits=1;
1330 1         4 $nfillbits++ while ($fillidx>=(1<<$nfillbits));
1331             } else {
1332 0         0 $nfillbits=0;
1333             }
1334 1 50       4 if ($lineidx>0) {
1335 0         0 $nlinebits=1;
1336 0         0 $nlinebits++ while ($lineidx>=(1<<$nlinebits));
1337             } else {
1338 1         2 $nlinebits=0;
1339             }
1340            
1341 1         3 $stream->flush_bits;
1342 1         3 $stream->set_bits($nfillbits, 4);
1343 1         3 $stream->set_bits($nlinebits, 4);
1344            
1345 1         11 $self->ShapeRecords->pack($stream, \$nfillbits, \$nlinebits);
1346             }
1347            
1348             sub unpack {
1349 1     1   3 my ($self, $stream)=@_;
1350            
1351 1         5 $self->FillStyles->unpack($stream);
1352 1         5 $self->LineStyles->unpack($stream);
1353 1         11 $self->SUPER::unpack($stream);
1354             }
1355            
1356             ##########
1357            
1358             package SWF::Element::SHAPERECORD1;
1359            
1360             sub unpack {
1361 10     10   20 my ($self, $stream, $nfillbits, $nlinebits)=@_;
1362            
1363 10 100       23 if ($stream->get_bits(1)) { # Edge
1364            
1365 8 50       36 if ($stream->get_bits(1)) {
1366 0         0 bless $self, 'SWF::Element::SHAPERECORDn::STRAIGHTEDGERECORD';
1367             } else {
1368 8         19 bless $self, 'SWF::Element::SHAPERECORDn::CURVEDEDGERECORD';
1369             }
1370 8         25 $self->_init;
1371 8         17 $self->unpack($stream);
1372            
1373             } else { # New Shape or End of Shape
1374            
1375 2         9 my $flags = $stream->get_bits(5);
1376 2 100       9 if ($flags==0) {
1377 1         8 bless $self, 'SWF::Element::SHAPERECORDn::ENDSHAPERECORD';
1378             } else {
1379 1         12 bless $self, ref($self).'::STYLECHANGERECORD';
1380 1         13 $self->_init;
1381 1         24 $self->unpack($stream, $nfillbits, $nlinebits, $flags);
1382             }
1383             }
1384             }
1385            
1386             sub pack {
1387 0     0   0 Carp::croak "Not enough data to pack ".ref($_[0]);
1388             }
1389            
1390             sub AUTOLOAD { # auto re-bless with proper sub class by specified accessor.
1391 9     9   18 my ($self, @param)=@_;
1392 9         10 my ($name, $class);
1393            
1394 9 50       23 return if $SWF::Element::SHAPERECORD1::AUTOLOAD =~/::DESTROY$/;
1395            
1396 9 50       50 Carp::croak "No such method: $SWF::Element::SHAPERECORD1::AUTOLOAD" unless $SWF::Element::SHAPERECORD1::AUTOLOAD=~/::([A-Z]\w*)$/;
1397 9         19 $name = $1;
1398 9         10 $class = ref($self);
1399            
1400 9         22 for my $subclass ("${class}::STYLECHANGERECORD", 'SWF::Element::SHAPERECORDn::STRAIGHTEDGERECORD', 'SWF::Element::SHAPERECORDn::CURVEDEDGERECORD') {
1401 25 100       86 $class=$subclass, last if $subclass->element_type($name);
1402             }
1403 9 50       24 Carp::croak "Element '$name' is NOT in $class " if $class eq ref($self);
1404            
1405 9         18 bless $self, $class;
1406 9         22 $self->$name(@param);
1407             }
1408            
1409             ##########
1410            
1411             package SWF::Element::SHAPERECORD1::STYLECHANGERECORD;
1412            
1413             sub pack {
1414 0     0   0 my ($self, $stream, $nfillbits, $nlinebits)=@_;
1415 0         0 my ($flags)=0;
1416            
1417 0         0 my $j=0;
1418 0         0 for my $i (qw/MoveDeltaX FillStyle0 FillStyle1 LineStyle/) {
1419 0 0       0 $flags |=(1<<$j) if defined $self->$i;
1420 0         0 $j++;
1421             }
1422 0         0 $stream->set_bits($flags, 6);
1423 0 0       0 $stream->set_sbits_list(5, $self->MoveDeltaX, $self->MoveDeltaY) if ($flags & 1);
1424 0 0       0 $stream->set_bits($self->FillStyle0, $$nfillbits) if ($flags & 2);
1425 0 0       0 $stream->set_bits($self->FillStyle1, $$nfillbits) if ($flags & 4);
1426 0 0       0 $stream->set_bits($self->LineStyle , $$nlinebits) if ($flags & 8);
1427             }
1428            
1429             sub unpack {
1430 0     0   0 my ($self, $stream, $nfillbits, $nlinebits, $flags)=@_;
1431            
1432 0 0       0 if ($flags & 1) { # MoveTo
1433 0         0 my ($nbits)=$stream->get_bits(5);
1434 0         0 $self->MoveDeltaX($stream->get_sbits($nbits));
1435 0         0 $self->MoveDeltaY($stream->get_sbits($nbits));
1436             }
1437 0 0       0 if ($flags & 2) { # FillStyle0
1438 0         0 $self->FillStyle0($stream->get_bits($$nfillbits));
1439             }
1440 0 0       0 if ($flags & 4) { # FillStyle1
1441 0         0 $self->FillStyle1($stream->get_bits($$nfillbits));
1442             }
1443 0 0       0 if ($flags & 8) { # LineStyle
1444 0         0 $self->LineStyle($stream->get_bits($$nlinebits));
1445             }
1446             }
1447            
1448             ##########
1449            
1450             package SWF::Element::SHAPERECORD2::STYLECHANGERECORD;
1451            
1452             sub pack {
1453 1     1   4 my ($self, $stream, $nfillbits, $nlinebits)=@_;
1454 1         2 my ($flags)=0;
1455            
1456 1         2 my $j=0;
1457 1         3 for my $i (qw/MoveDeltaX FillStyle0 FillStyle1 LineStyle/) {
1458 4 100       12 $flags |=(1<<$j) if defined $self->$i;
1459 4         10 $j++;
1460             }
1461 1 50 33     2 $flags |= 16 if @{$self->FillStyles}>0 or @{$self->LineStyles}>0;
  1         3  
  1         4  
1462 1         4 $stream->set_bits($flags, 6);
1463 1 50       7 $stream->set_sbits_list(5, $self->MoveDeltaX, $self->MoveDeltaY) if ($flags & 1);
1464 1 50       19 $stream->set_bits($self->FillStyle0, $$nfillbits) if ($flags & 2);
1465 1 50       5 $stream->set_bits($self->FillStyle1, $$nfillbits) if ($flags & 4);
1466 1 50       4 $stream->set_bits($self->LineStyle , $$nlinebits) if ($flags & 8);
1467 1 50       5 if ($flags & 16) { # NewStyles (SHAPERECORD2,3)
1468 0         0 my ($fillidx, $lineidx)=($#{$self->FillStyles}+1, $#{$self->LineStyles}+1);
  0         0  
  0         0  
1469 0         0 $self->FillStyles->pack($stream);
1470 0         0 $self->LineStyles->pack($stream);
1471 0 0       0 if ($fillidx>0) {
1472 0         0 $$nfillbits=1;
1473 0         0 $$nfillbits++ while ($fillidx>=(1<<$$nfillbits));
1474             } else {
1475 0         0 $$nfillbits=0;
1476             }
1477 0 0       0 if ($lineidx>0) {
1478 0         0 $$nlinebits=1;
1479 0         0 $$nlinebits++ while ($lineidx>=(1<<$$nlinebits));
1480             } else {
1481 0         0 $$nlinebits=0;
1482             }
1483 0         0 $stream->set_bits($$nfillbits, 4);
1484 0         0 $stream->set_bits($$nlinebits, 4);
1485             }
1486             }
1487            
1488             sub unpack {
1489 1     1   4 my ($self, $stream, $nfillbits, $nlinebits, $flags)=@_;
1490            
1491 1 50       5 if ($flags & 1) { # MoveTo
1492 1         5 my ($nbits)=$stream->get_bits(5);
1493 1         4 $self->MoveDeltaX($stream->get_sbits($nbits));
1494 1         5 $self->MoveDeltaY($stream->get_sbits($nbits));
1495             }
1496 1 50       5 if ($flags & 2) { # FillStyle0
1497 1         4 $self->FillStyle0($stream->get_bits($$nfillbits));
1498             }
1499 1 50       7 if ($flags & 4) { # FillStyle1
1500 0         0 $self->FillStyle1($stream->get_bits($$nfillbits));
1501             }
1502 1 50       4 if ($flags & 8) { # LineStyle
1503 0         0 $self->LineStyle($stream->get_bits($$nlinebits));
1504             }
1505 1 50       6 if ($flags & 16) { # NewStyles (SHAPERECORD2,3)
1506 0         0 $self->FillStyles->unpack($stream);
1507 0         0 $self->LineStyles->unpack($stream);
1508 0         0 $$nfillbits=$stream->get_bits(4);
1509 0         0 $$nlinebits=$stream->get_bits(4);
1510             }
1511             }
1512            
1513             ##########
1514            
1515             package SWF::Element::SHAPERECORDn::STRAIGHTEDGERECORD;
1516            
1517             sub unpack {
1518 0     0   0 my ($self, $stream)=@_;
1519 0         0 my $nbits = $stream->get_bits(4)+2;
1520 0 0       0 if ($stream->get_bits(1)) {
1521 0         0 $self->DeltaX($stream->get_sbits($nbits));
1522 0         0 $self->DeltaY($stream->get_sbits($nbits));
1523             } else {
1524 0 0       0 if ($stream->get_bits(1)) {
1525 0         0 $self->DeltaX(0);
1526 0         0 $self->DeltaY($stream->get_sbits($nbits));
1527             } else {
1528 0         0 $self->DeltaX($stream->get_sbits($nbits));
1529 0         0 $self->DeltaY(0);
1530             }
1531             }
1532             }
1533            
1534             sub pack {
1535 0     0   0 my ($self, $stream)=@_;
1536 0         0 my ($dx, $dy, $nbits);
1537            
1538 0         0 $stream->set_bits(3,2); # Type=1, Edge=1
1539            
1540 0         0 $dx=$self->DeltaX;
1541 0         0 $dy=$self->DeltaY;
1542 0         0 $nbits=SWF::BinStream::Write::get_maxbits_of_sbits_list($dx, $dy);
1543 0 0       0 $nbits=2 if ($nbits<2);
1544 0         0 $stream->set_bits($nbits-2,4);
1545 0 0       0 if ($dx==0) {
    0          
1546 0         0 $stream->set_bits(1,2); # GeneralLine=0, Vert=1
1547 0         0 $stream->set_sbits($dy, $nbits);
1548             } elsif ($dy==0) {
1549 0         0 $stream->set_bits(0,2); # GeneralLine=0, Vert=0
1550 0         0 $stream->set_sbits($dx, $nbits);
1551             } else {
1552 0         0 $stream->set_bits(1,1); # GeneralLine=1
1553 0         0 $stream->set_sbits($dx, $nbits);
1554 0         0 $stream->set_sbits($dy, $nbits);
1555             }
1556             }
1557            
1558             ##########
1559            
1560             package SWF::Element::SHAPERECORDn::CURVEDEDGERECORD;
1561            
1562             sub unpack {
1563 8     8   11 my ($self, $stream)=@_;
1564 8         22 my ($nbits)=$stream->get_bits(4)+2;
1565            
1566 8         24 $self->ControlDeltaX($stream->get_sbits($nbits));
1567 8         23 $self->ControlDeltaY($stream->get_sbits($nbits));
1568 8         21 $self->AnchorDeltaX($stream->get_sbits($nbits));
1569 8         23 $self->AnchorDeltaY($stream->get_sbits($nbits));
1570             }
1571            
1572             sub pack {
1573 8     8   10 my ($self, $stream)=@_;
1574            
1575 8         17 my @d=( $self->ControlDeltaX,
1576             $self->ControlDeltaY,
1577             $self->AnchorDeltaX ,
1578             $self->AnchorDeltaY );
1579 8         259 my $nbits = SWF::BinStream::Write::get_maxbits_of_sbits_list(@d);
1580 8 50       22 $nbits=2 if ($nbits<2);
1581 8         22 $stream->set_bits(2,2); # Type=1, Edge=0
1582 8         41 $stream->set_bits($nbits-2,4);
1583 8         48 for my $i (@d) {
1584 32         367 $stream->set_sbits($i, $nbits);
1585             }
1586             }
1587            
1588             ##########
1589            
1590             package SWF::Element::Tag;
1591            
1592             my @tagname;
1593            
1594             sub new {
1595 12     12   137 my ($class, %headerdata)=@_;
1596 12         15 my $self;
1597 12         22 my $length = $headerdata{Length};
1598 12         21 my $tag = $headerdata{Tag};
1599            
1600 12         25 $self = [];
1601 12         41 delete @headerdata{'Length','Tag'};
1602            
1603 12 100       28 if (defined $tag) {
1604 6         20 $class = $class->_tag_class($tag);
1605 6         30 bless $self, $class;
1606             } else {
1607 6   33     27 $class = ref($class)||$class;
1608 6         17 bless $self, $class;
1609             }
1610 12         72 $self->_init($length, $tag);
1611 12 100       69 $self->configure(%headerdata) if %headerdata;
1612 12         80 $self;
1613             }
1614            
1615             sub _init {
1616 12     12   25 my ($self, $length)=@_;
1617            
1618 12         62 $self->Length($length);
1619             }
1620            
1621             sub Length {
1622 19     19   33 my ($self, $len) = @_;
1623 19 100       54 $self->[0] = $len if defined $len;
1624 19         111 $self->[0];
1625             }
1626            
1627             sub is_tagtype {
1628 5     5   12 my ($self, $type) = @_;
1629            
1630 5         170 return $self->isa("SWF::Element::Tag::${type}");
1631             }
1632            
1633             sub unpack { # unpack tag header, re-bless, and unpack individual data for the tag.
1634 0     0   0 my ($self, $stream)=@_;
1635 0         0 my ($header, $tag, $length);
1636            
1637 0         0 $header = $stream->get_UI16;
1638 0         0 $tag = $header>>6;
1639 0         0 $length = ($header & 0x3f);
1640 0 0       0 $length = $stream->get_UI32 if ($length == 0x3f);
1641 0         0 my $class = $self->_tag_class($tag);
1642 0         0 bless $self, $class;
1643 0         0 $self->_init($length, $tag);
1644 0         0 $self->unpack($stream);
1645             }
1646            
1647            
1648             sub pack {
1649 0     0   0 Carp::croak "Can't pack the unidentified tag.";
1650             }
1651            
1652             sub _unpack {
1653 0     0   0 Carp::confess "Unexpected _unpack";
1654             }
1655            
1656             sub _pack {
1657 0     0   0 Carp::confess "Unexpected _pack";
1658             }
1659            
1660            
1661             sub _tag_class {
1662 6   50 6   34 return 'SWF::Element::Tag::'.($tagname[$_[1]]||'Unknown');
1663             }
1664            
1665             sub _create_tag {
1666 1     1   17 no strict 'refs';
  1         2  
  1         37165  
1667            
1668 48     48   91 my $tagname = shift;
1669 48         59 my $tagno = shift;
1670 48         50 my $isa = shift;
1671 48         198 $_ = "Tag::$_" for @$isa;
1672 48         285 SWF::Element::_create_class("Tag::$tagname", $isa, @_, 1);
1673            
1674 48         105 my $tag_package = "SWF::Element::Tag::${tagname}";
1675 48         64 my $offset = 0;
1676 48         97 while (@_) {
1677 108         131 my $k = shift;
1678 108         115 my $v = shift;
1679 108         112 my $o = 0;
1680 108 100 100     497 if ($v eq 'ID' or $v eq 'Depth') {
    100          
1681 37         42 $v = 'lookahead_UI16';
1682 37         36 $o = 2;
1683             } elsif ($v =~ /^\$./) {
1684 33         104 $v =~ s/^./lookahead_/;
1685 33         150 ($o) = $v=~/(\d+)$/;
1686 33         68 $o >>=3;
1687             } else {
1688 38         61 last;
1689             }
1690 70 100       76 unless (defined &{"${tag_package}::lookahead_$k"}) {
  70         477  
1691 69         87 my $offset1 = $offset;
1692 69         357 *{"${tag_package}::lookahead_$k"} = sub {
1693 0     0   0 my ($self, $stream) = @_;
1694 0         0 $self->$k($stream->$v($offset1));
1695             }
1696 69         315 }
1697            
1698 70         236 $offset += $o;
1699             }
1700            
1701 48         83 $tagname[$tagno] = $tagname;
1702 48     6   165 *{"${tag_package}::tag_number"} = sub {$tagno};
  48         261  
  6         13  
1703 48     0   172 *{"${tag_package}::tag_name"} = sub {$tagname};
  48         235  
  0         0  
1704 48         75 @{"${tag_package}::Packed::ISA"} = ( 'SWF::Element::Tag::Packed', $tag_package );
  48         1492  
1705             }
1706            
1707             sub _create_pack {
1708 26     26   44 my $tagname = shift;
1709 26         73 SWF::Element::_create_pack("Tag::$tagname",'_');
1710             }
1711            
1712             ## Tag types ##
1713            
1714             @SWF::Element::Tag::Definition::ISA = ('SWF::Element::Tag::Identified');
1715             @SWF::Element::Tag::Shape::ISA = ('SWF::Element::Tag::Definition');
1716             @SWF::Element::Tag::Bitmap::ISA = ('SWF::Element::Tag::Definition');
1717             @SWF::Element::Tag::LossLessBitmap::ISA = ('SWF::Element::Tag::Bitmap');
1718             @SWF::Element::Tag::JPEG::ISA = ('SWF::Element::Tag::Bitmap');
1719             @SWF::Element::Tag::Font::ISA = ('SWF::Element::Tag::Definition');
1720             @SWF::Element::Tag::Text::ISA = ('SWF::Element::Tag::Definition');
1721             @SWF::Element::Tag::Sound::ISA = ('SWF::Element::Tag::Definition');
1722             @SWF::Element::Tag::Button::ISA = ('SWF::Element::Tag::Definition');
1723             @SWF::Element::Tag::Sprite::ISA = ('SWF::Element::Tag::Definition');
1724             @SWF::Element::Tag::Video::ISA = ('SWF::Element::Tag::Definition');
1725             @SWF::Element::Tag::DisplayList::ISA = ('SWF::Element::Tag::Identified');
1726             @SWF::Element::Tag::Control::ISA = ('SWF::Element::Tag::Identified');
1727            
1728             @SWF::Element::Tag::ValidInSprite::ISA = ('SWF::Element::Tag');
1729             @SWF::Element::Tag::ActionContainer::ISA = ('SWF::Element::Tag');
1730             @SWF::Element::Tag::AlwaysLongHeader::ISA = ('SWF::Element::Tag');
1731            
1732             ## Shapes ##
1733            
1734             _create_tag('DefineShape', 2, ['Shape'],
1735            
1736             ShapeID => 'ID',
1737             ShapeBounds => 'RECT',
1738             Shapes => 'SHAPEWITHSTYLE1');
1739             _create_pack('DefineShape');
1740            
1741             _create_tag('DefineShape2', 22, ['DefineShape'],
1742            
1743             ShapeID => 'ID',
1744             ShapeBounds => 'RECT',
1745             Shapes => 'SHAPEWITHSTYLE2');
1746             _create_pack('DefineShape2');
1747            
1748             _create_tag('DefineShape3', 32, ['DefineShape'],
1749            
1750             ShapeID => 'ID',
1751             ShapeBounds => 'RECT',
1752             Shapes => 'SHAPEWITHSTYLE3');
1753             _create_pack('DefineShape3');
1754            
1755             _create_tag('DefineMorphShape', 46, ['Shape'],
1756            
1757             CharacterID => 'ID',
1758             StartBounds => 'RECT',
1759             EndBounds => 'RECT',
1760             MorphFillStyles => 'Array::MORPHFILLSTYLEARRAY',
1761             MorphLineStyles => 'Array::MORPHLINESTYLEARRAY',
1762             StartEdges => 'SHAPE',
1763             EndEdges => 'SHAPE');
1764            
1765             ## Bitmaps ##
1766            
1767             _create_tag('DefineBits', 6, ['JPEG'],
1768            
1769             CharacterID => 'ID',
1770             JPEGData => 'BinData');
1771            
1772             _create_tag('JPEGTables', 8, ['JPEG'],
1773            
1774             JPEGData => 'BinData');
1775            
1776             _create_tag('DefineBitsJPEG2', 21, ['DefineBits'],
1777            
1778             CharacterID => 'ID',
1779             JPEGData => 'BinData');
1780            
1781             _create_tag('DefineBitsJPEG3', 35, ['DefineBitsJPEG2'],
1782            
1783             CharacterID => 'ID',
1784             JPEGData => 'BinData',
1785             BitmapAlphaData => 'BinData');
1786            
1787             _create_tag('DefineBitsLossless', 20, ['LossLessBitmap', 'AlwaysLongHeader'],
1788            
1789             CharacterID => 'ID',
1790             BitmapFormat => '$UI8',
1791             BitmapWidth => '$UI16',
1792             BitmapHeight => '$UI16',
1793             BitmapColorTableSize => '$UI8',
1794             ZlibBitmapData => 'BinData',
1795             );
1796            
1797             _create_tag('DefineBitsLossless2', 36, ['DefineBitsLossless'],
1798            
1799             CharacterID => 'ID',
1800             BitmapFormat => '$UI8',
1801             BitmapWidth => '$UI16',
1802             BitmapHeight => '$UI16',
1803             BitmapColorTableSize => '$UI8',
1804             ZlibBitmapData => 'BinData',
1805             );
1806            
1807             ## Buttons ##
1808            
1809             _create_tag('DefineButton', 7, ['Button', 'ActionContainer'],
1810            
1811             ButtonID => 'ID',
1812             Characters => 'Array::BUTTONRECORDARRAY1',
1813             Actions => 'Array::ACTIONRECORDARRAY');
1814             _create_pack('DefineButton');
1815            
1816             _create_tag('DefineButton2', 34, ['Button', 'ActionContainer'],
1817            
1818             ButtonID => 'ID',
1819             Flags => '$UI8',
1820             Characters => 'Array::BUTTONRECORDARRAY2',
1821             Actions => 'Array::BUTTONCONDACTIONARRAY');
1822            
1823             _create_tag('DefineButtonCxform', 23, ['Button'],
1824            
1825             ButtonID => 'ID',
1826             ButtonColorTransform => 'CXFORM');
1827             _create_pack('DefineButtonCxform');
1828            
1829             _create_tag('DefineButtonSound', 17, ['Button'],
1830            
1831             ButtonID => 'ID',
1832             ButtonSoundChar0 => 'ID', ButtonSoundInfo0 => 'SOUNDINFO',
1833             ButtonSoundChar1 => 'ID', ButtonSoundInfo1 => 'SOUNDINFO',
1834             ButtonSoundChar2 => 'ID', ButtonSoundInfo2 => 'SOUNDINFO',
1835             ButtonSoundChar3 => 'ID', ButtonSoundInfo3 => 'SOUNDINFO');
1836            
1837             ## Fonts & Texts ##
1838            
1839             _create_tag('DefineFont', 10, ['Font'],
1840            
1841             FontID => 'ID', GlyphShapeTable => 'Array::GLYPHSHAPEARRAY1');
1842             _create_pack('DefineFont');
1843            
1844             _create_tag('DefineFontInfo', 13, ['Font'],
1845            
1846             FontID => 'ID',
1847             FontName => 'PSTRING',
1848             FontFlags => '$UI8',
1849             CodeTable => 'Array::CODETABLE');
1850            
1851             _create_tag('DefineFontInfo2', 62, ['DefineFontInfo'],
1852            
1853             FontID => 'ID',
1854             FontName => 'PSTRING',
1855             FontFlags => '$UI8',
1856             LanguageCode => '$UI8',
1857             CodeTable => 'Array::CODETABLE');
1858            
1859             _create_tag('DefineFont2', 48, ['Font'],
1860            
1861             FontID => 'ID',
1862             FontFlags => '$UI8',
1863             LanguageCode => '$UI8',
1864             FontName => 'PSTRING',
1865             GlyphShapeTable => 'Array::GLYPHSHAPEARRAY2',
1866             CodeTable => 'Array::CODETABLE',
1867             FontAscent => '$SI16',
1868             FontDescent => '$SI16',
1869             FontLeading => '$SI16',
1870             FontAdvanceTable => 'Array::FONTADVANCETABLE',
1871             FontBoundsTable => 'Array::FONTBOUNDSTABLE',
1872             FontKerningTable => 'FONTKERNINGTABLE');
1873            
1874             _create_tag('DefineText', 11, ['Text'],
1875            
1876             CharacterID => 'ID',
1877             TextBounds => 'RECT',
1878             TextMatrix => 'MATRIX',
1879             TextRecords => 'Array::TEXTRECORDARRAY1');
1880             _create_pack('DefineText');
1881            
1882             _create_tag('DefineText2', 33, ['DefineText'],
1883            
1884             CharacterID => 'ID',
1885             TextBounds => 'RECT',
1886             TextMatrix => 'MATRIX',
1887             TextRecords => 'Array::TEXTRECORDARRAY2');
1888             _create_pack('DefineText2');
1889            
1890             _create_tag('DefineEditText', 37, ['Text'],
1891            
1892             CharacterID => 'ID',
1893             Bounds => 'RECT',
1894             Flags => '$UI16',
1895             FontID => 'ID',
1896             FontHeight => '$UI16',
1897             TextColor => 'RGBA',
1898             MaxLength => '$UI16',
1899             Align => '$UI8',
1900             LeftMargin => '$UI16',
1901             RightMargin => '$UI16',
1902             Indent => '$UI16',
1903             Leading => '$UI16',
1904             VariableName => 'STRING',
1905             InitialText => 'STRING');
1906            
1907             ## Sounds ##
1908            
1909             _create_tag('DefineSound', 14, ['Sound'],
1910            
1911             SoundID => 'ID',
1912             Flags => '$UI8',
1913             SoundSampleCount => '$UI32',
1914             SoundData => 'BinData');
1915            
1916             _create_tag('StartSound', 15, ['Identified', 'ValidInSprite'],
1917            
1918             SoundID => 'ID',
1919             SoundInfo => 'SOUNDINFO');
1920             _create_pack('StartSound');
1921            
1922             _create_tag('SoundStreamBlock', 19, ['Identified', 'ValidInSprite'],
1923            
1924             StreamSoundData => 'BinData');
1925            
1926             _create_tag('SoundStreamHead', 18, ['Identified', 'ValidInSprite'],
1927            
1928             Flags => '$UI16',
1929             StreamSoundSampleCount => '$UI16',
1930             LatencySeek => '$SI16');
1931            
1932             _create_tag('SoundStreamHead2', 45, ['SoundStreamHead'],
1933            
1934             Flags => '$UI16',
1935             StreamSoundSampleCount => '$UI16',
1936             LatencySeek => '$SI16');
1937            
1938             ## Sprites ##
1939            
1940             _create_tag('DefineSprite', 39, ['Sprite'],
1941            
1942             SpriteID => 'ID',
1943             FrameCount => '$UI16',
1944             ControlTags => 'Array::TAGARRAY',
1945             TagStream => 'TAGSTREAM');
1946            
1947             ## Display list ##
1948            
1949             _create_tag('PlaceObject', 4, ['DisplayList', 'ValidInSprite'],
1950            
1951             CharacterID => 'ID',
1952             Depth => 'Depth',
1953             Matrix => 'MATRIX',
1954             ColorTransform => 'CXFORM');
1955            
1956             _create_tag('PlaceObject2', 26, ['DisplayList', 'ActionContainer', 'ValidInSprite'],
1957            
1958             Flags => '$UI8',
1959             Depth => 'Depth',
1960             CharacterID => 'ID',
1961             Matrix => 'MATRIX',
1962             ColorTransform => 'CXFORMWITHALPHA',
1963             Ratio => '$UI16',
1964             Name => 'STRING',
1965             ClipDepth => 'Depth',
1966             ClipActions => 'Array::CLIPACTIONRECORDARRAY');
1967            
1968             _create_tag('RemoveObject', 5, ['DisplayList', 'ValidInSprite'],
1969            
1970             CharacterID => 'ID', Depth => 'Depth' );
1971             _create_pack('RemoveObject');
1972            
1973             _create_tag('RemoveObject2', 28, ['DisplayList', 'ValidInSprite'],
1974            
1975             Depth => 'Depth' );
1976             _create_pack('RemoveObject2');
1977            
1978             _create_tag('ShowFrame', 1, ['DisplayList', 'ValidInSprite']);
1979             _create_pack('ShowFrame');
1980            
1981             ## Control ##
1982            
1983             _create_tag('SetBackgroundColor', 9, ['Control'],
1984            
1985             BackgroundColor => 'RGB' );
1986             _create_pack('SetBackgroundColor');
1987            
1988             _create_tag('FrameLabel', 43, ['Control', 'ValidInSprite'],
1989            
1990             Name => 'STRING',
1991             NamedAnchorFlag => '$UI8' );
1992            
1993             _create_tag('Protect', 24, ['Control'],
1994            
1995             Reserved => '$UI16',
1996             Password => 'STRING' );
1997            
1998             _create_tag('EnableDebugger', 58, ['Control'],
1999            
2000             Reserved => '$UI16',
2001             Password => 'STRING' );
2002             _create_pack('EnableDebugger');
2003            
2004             _create_tag('EnableDebugger2', 64, ['Control'],
2005            
2006             Reserved => '$UI16',
2007             Password => 'STRING' );
2008             _create_pack('EnableDebugger2');
2009            
2010             _create_tag('ScriptLimits', 65, ['Control'],
2011            
2012             MaxRecurtionDepth => '$UI16',
2013             ScriptTimeoutSeconds => '$UI16' );
2014             _create_pack('ScriptLimits');
2015            
2016             _create_tag('SetTabIndex', 66, ['Control'],
2017            
2018             Depth => 'Depth',
2019             TabIndex => '$UI16' );
2020             _create_pack('SetTabIndex');
2021            
2022            
2023             _create_tag('End', 0, ['Control', 'ValidInSprite']);
2024             _create_pack('End');
2025            
2026             _create_tag('ExportAssets', 56, ['Control'],
2027            
2028             Assets => 'Array::ASSETARRAY');
2029             _create_pack('ExportAssets');
2030            
2031             _create_tag('ImportAssets', 57, ['Control', 'Definition'],
2032            
2033             URL => 'STRING',
2034             Assets => 'Array::ASSETARRAY');
2035             _create_pack('ImportAssets');
2036            
2037             ## Actions ##
2038            
2039             _create_tag('DoAction', 12, ['Identified', 'ActionContainer', 'ValidInSprite'],
2040            
2041             Actions => 'Array::ACTIONRECORDARRAY');
2042             _create_pack('DoAction');
2043            
2044             _create_tag('DoInitAction', 59, ['Definition', 'ActionContainer'],
2045            
2046             SpriteID => 'ID',
2047             Actions => 'Array::ACTIONRECORDARRAY');
2048             _create_pack('DoInitAction');
2049            
2050             ## Video ##
2051            
2052             _create_tag('DefineVideoStream', 60, ['Video'],
2053            
2054             CharacterID => 'ID',
2055             NumFrames => '$UI16',
2056             Width => '$UI16',
2057             Height => '$UI16',
2058             VideoFlags => '$UI8',
2059             CodecID => '$UI8');
2060             _create_pack('DefineVideoStream');
2061            
2062             _create_tag('VideoFrame', 61, ['Video'],
2063            
2064             StreamID => 'ID',
2065             FrameNum => '$UI16',
2066             VideoData => 'BinData');
2067             _create_pack('VideoFrame');
2068            
2069             ## others? ##
2070            
2071             _create_tag('FreeCharacter', 3, ['Control'],
2072            
2073             CharacterID => 'ID');
2074             _create_pack('FreeCharacter');
2075            
2076             _create_tag('NameCharacter', 40, ['Control'],
2077            
2078             ID => 'ID',
2079             Name => 'STRING');
2080             _create_pack('NameCharacter');
2081            
2082            
2083            
2084             ### Identified Tag base ###
2085            
2086             package SWF::Element::Tag::Identified;
2087            
2088             sub unpack {
2089 6     6   158 my $self = shift;
2090 6         7 my $stream = shift;
2091            
2092 6         18 my $start = $stream->tell;
2093 6   100     17 my $length = $self->Length || 0;
2094 6 100       101 $self->_unpack($stream, @_) if $length>0;
2095 6         107 $stream->flush_bits;
2096 6         19 my $read = $stream->tell - $start;
2097 6 50       34 if ($read < $length) {
    50          
2098 0         0 $stream->get_string($length-$read); # Skip the rest of tag data.
2099             } elsif ($read > $length) {
2100 0         0 Carp::croak ref($self)." unpacked $read bytes in excess of the described tag length, $length bytes. The SWF may be collapsed or the module bug??";
2101             }
2102             }
2103            
2104             sub pack {
2105 6     6   12 my ($self, $stream)=@_;
2106 6         25 my $substream = $stream->sub_stream;
2107            
2108 6         165 $self->_pack($substream);
2109 6         33 my $header = $self->tag_number<<6;
2110 6         27 my $len = $substream->tell;
2111 6 100 66     158 if ($len >= 0x3f or $self->is_tagtype('AlwaysLongHeader')) {
2112 1         2 $header |= 0x3f;
2113 1         6 $stream->set_UI16($header);
2114 1         12 $stream->set_UI32($len);
2115             } else {
2116 5         24 $stream->set_UI16($header|$len);
2117             }
2118 6         25 $substream->flush_stream;
2119             }
2120            
2121            
2122             #### Packed tag ####
2123             ##########
2124            
2125             package SWF::Element::Tag::Packed;
2126            
2127             #@SWF::Element::Tag::Packed::ISA = ('SWF::Element::Tag::Identified');
2128            
2129             SWF::Element::_create_class
2130             ( 'Tag::Packed', ['Tag::Identified'],
2131             Tag => '$',
2132             Data => 'BinData',
2133             1 );
2134            
2135             sub _init {
2136 0     0   0 my $self = shift;
2137 0         0 my $tag = $_[1];
2138            
2139 0         0 $self->SUPER::_init(@_);
2140 0         0 $self->Tag($tag);
2141             }
2142            
2143             sub _tag_class {
2144 0 0   0   0 return $tagname[$_[1]] ? 'SWF::Element::Tag::'.$tagname[$_[1]].'::Packed' : 'SWF::Element::Tag::Unknown';
2145             }
2146            
2147             sub _unpack {
2148 0     0   0 my ($self, $stream)=@_;
2149            
2150 0         0 $self->Data->unpack($stream, $self->Length);
2151             }
2152            
2153             sub _pack {
2154 0     0   0 my ($self, $stream)=@_;
2155            
2156 0         0 $self->Data->pack($stream);
2157             }
2158            
2159             #### Unknown ####
2160             ##########
2161            
2162             package SWF::Element::Tag::Unknown;
2163            
2164             @SWF::Element::Tag::Unknown::ISA = ('SWF::Element::Tag::Packed');
2165            
2166             SWF::Element::_create_class
2167             ( 'Tag::Unknown', ['Tag::Packed'],
2168             Tag => '$',
2169             Data => 'BinData',
2170             1 );
2171            
2172             sub _init {
2173 0     0   0 my $self = shift;
2174 0         0 my $tag = $_[1];
2175            
2176 0         0 $self->SUPER::_init(@_);
2177 0         0 Carp::carp "Tag No. $tag is unknown";
2178             }
2179            
2180 0     0   0 sub tag_name {'Unknown'}
2181 0     0   0 sub tag_number {shift->Tag}
2182            
2183             #### Shapes ####
2184             ########
2185            
2186             package SWF::Element::Tag::DefineMorphShape;
2187            
2188             sub _unpack {
2189 0     0   0 my ($self, $stream)=@_;
2190            
2191 0         0 $self->CharacterID->unpack($stream);
2192 0         0 $self->StartBounds->unpack($stream);
2193 0         0 $self->EndBounds ->unpack($stream);
2194 0         0 $stream->get_UI32; # Skip Offset
2195 0         0 $self->MorphFillStyles->unpack($stream);
2196 0         0 $self->MorphLineStyles->unpack($stream);
2197 0         0 $stream->flush_bits;
2198 0         0 $self->StartEdges->unpack($stream);
2199 0         0 $stream->flush_bits;
2200 0         0 $self->EndEdges->unpack($stream);
2201             }
2202            
2203             sub _pack {
2204 0     0   0 my ($self, $stream)=@_;
2205            
2206 0         0 $self->CharacterID->pack($stream);
2207 0         0 $self->StartBounds->pack($stream);
2208 0         0 $self->EndBounds ->pack($stream);
2209             {
2210 0         0 my $tempstream=$stream->sub_stream;
  0         0  
2211 0         0 my ($nfillbits, $nlinebits) = (0, 0);
2212 0         0 my ($fillidx, $lineidx) = ($#{$self->MorphFillStyles}+1, $#{$self->MorphLineStyles}+1);
  0         0  
  0         0  
2213 0 0       0 if ($fillidx>0) {
2214 0         0 $nfillbits=1;
2215 0         0 $nfillbits++ while ($fillidx>=(1<<$nfillbits));
2216             }
2217 0 0       0 if ($lineidx>0) {
2218 0         0 $nlinebits=1;
2219 0         0 $nlinebits++ while ($lineidx>=(1<<$nlinebits));
2220             }
2221 0         0 $self->MorphFillStyles->pack($tempstream);
2222 0         0 $self->MorphLineStyles->pack($tempstream);
2223 0         0 $tempstream->flush_bits;
2224 0         0 $self->StartEdges->pack($tempstream, $nfillbits, $nlinebits);
2225 0         0 $tempstream->flush_bits;
2226 0         0 $stream->set_UI32($tempstream->tell);
2227 0         0 $tempstream->flush_stream;
2228             }
2229 0         0 $self->EndEdges->pack($stream, 0, 0);
2230 0         0 $stream->flush_bits;
2231             }
2232            
2233             ##########
2234            
2235             package SWF::Element::MORPHFILLSTYLE;
2236            
2237             sub pack {
2238 0     0   0 my ($self, $stream)=@_;
2239 0         0 my $style=$self->FillStyleType;
2240 0         0 $stream->set_UI8($style);
2241 0 0 0     0 if ($style==0x00) {
    0 0        
    0          
2242 0         0 $self->StartColor->pack($stream);
2243 0         0 $self->EndColor->pack($stream);
2244             } elsif ($style==0x10 or $style==0x12) {
2245 0         0 $self->StartGradientMatrix->pack($stream);
2246 0         0 $self->EndGradientMatrix->pack($stream);
2247 0         0 $self->Gradient->pack($stream);
2248             } elsif ($style>=0x40 or $style<=0x43) {
2249 0         0 $self->BitmapID->pack($stream);
2250 0         0 $self->StartBitmapMatrix->pack($stream);
2251 0         0 $self->EndBitmapMatrix->pack($stream);
2252             }
2253             }
2254            
2255             sub unpack {
2256 0     0   0 my ($self, $stream)=@_;
2257 0         0 my $style = $self->FillStyleType($stream->get_UI8);
2258 0 0 0     0 if ($style==0x00) {
    0 0        
    0          
2259 0         0 $self->StartColor->unpack($stream);
2260 0         0 $self->EndColor->unpack($stream);
2261             } elsif ($style==0x10 or $style==0x12) {
2262 0         0 $self->StartGradientMatrix->unpack($stream);
2263 0         0 $self->EndGradientMatrix->unpack($stream);
2264 0         0 $self->Gradient->unpack($stream);
2265             } elsif ($style<=0x40 or $style<=0x43) {
2266 0         0 $self->BitmapID->unpack($stream);
2267 0         0 $self->StartBitmapMatrix->unpack($stream);
2268 0         0 $self->EndBitmapMatrix->unpack($stream);
2269             }
2270             }
2271            
2272            
2273             #### Bitmaps ####
2274             ##########
2275            
2276             package SWF::Element::Tag::DefineBits;
2277            
2278             sub _unpack {
2279 0     0   0 my ($self, $stream)=@_;
2280            
2281 0         0 $self->CharacterID->unpack($stream);
2282 0         0 $self->JPEGData->unpack($stream, $self->Length - 2);
2283             }
2284            
2285             sub _pack {
2286 0     0   0 my ($self, $stream)=@_;
2287            
2288 0         0 $self->CharacterID->pack($stream);
2289 0         0 $self->JPEGData->pack($stream);
2290             }
2291            
2292             ##########
2293            
2294             package SWF::Element::Tag::DefineBitsJPEG2;
2295            
2296             sub _unpack {
2297 0     0   0 my ($self, $stream)=@_;
2298            
2299 0         0 $self->CharacterID->unpack($stream);
2300             # $self->_unpack_JPEG($stream, $self->Length - 2);
2301 0         0 $self->JPEGData->unpack($stream, $self->Length - 2);
2302             }
2303            
2304             =pod
2305            
2306             sub _unpack_JPEG {
2307             my ($self, $stream, $len) = @_;
2308             my ($data1, $data2);
2309            
2310             while (!$data2 and $len > 0) {
2311             my $size = ($len > 1000) ? 1000 : $len;
2312             $data1 = $stream->get_string($size);
2313             $len -= $size;
2314             if ($data1 =~/\xff$/ and $len>0) {
2315             $data1 .= $stream->get_string(1);
2316             $len--;
2317             }
2318             ($data1, $data2) = split /\xff\xd9/, $data1;
2319             $self->BitmapJPEGEncoding->add($data1);
2320             }
2321             $self->BitmapJPEGEncoding->add("\xff\xd9");
2322            
2323             $self->BitmapJPEGImage($data2);
2324             while ($len > 0) {
2325             my $size = ($len > 1000) ? 1000 : $len;
2326             $data1 = $stream->get_string($size);
2327             $len -= $size;
2328             $self->BitmapJPEGImage->add($data1);
2329             }
2330             }
2331            
2332             =cut
2333            
2334             ##########
2335            
2336             package SWF::Element::Tag::DefineBitsJPEG3;
2337            
2338             sub _unpack {
2339 0     0   0 my ($self, $stream)=@_;
2340            
2341 0         0 $self->CharacterID->unpack($stream);
2342 0         0 my $offset = $stream->get_UI32;
2343             # $self->_unpack_JPEG($stream, $offset);
2344 0         0 $self->JPEGData->unpack($stream, $offset);
2345 0         0 $self->BitmapAlphaData->unpack($stream, $self->Length - $offset - 6);
2346             }
2347            
2348             sub _pack {
2349 0     0   0 my ($self, $stream)=@_;
2350            
2351 0         0 $self->CharacterID->pack($stream);
2352 0         0 $stream->set_UI32($self->JPEGData->Length);
2353 0         0 $self->JPEGData->pack($stream);
2354 0         0 $self->BitmapAlphaData->pack($stream);
2355             }
2356            
2357             ##########
2358            
2359             package SWF::Element::Tag::DefineBitsLossless;
2360            
2361             sub _unpack {
2362 0     0   0 my ($self, $stream)=@_;
2363 0         0 my $length=$self->Length - 7;
2364            
2365             # delete @{$self}{qw/ColorTable BitmapImage/};
2366            
2367 0         0 $self->CharacterID->unpack($stream);
2368 0         0 $self->BitmapFormat($stream->get_UI8);
2369 0         0 $self->BitmapWidth($stream->get_UI16);
2370 0         0 $self->BitmapHeight($stream->get_UI16);
2371 0 0       0 if ($self->BitmapFormat == 3) {
2372 0         0 $self->BitmapColorTableSize($stream->get_UI8);
2373 0         0 $length--;
2374             }
2375 0         0 $self->ZlibBitmapData->unpack($stream, $length);
2376             # $self->decompress;
2377             }
2378            
2379             sub _pack {
2380 0     0   0 my ($self, $stream)=@_;
2381            
2382             # $self->compress if defined $self->{'ColorTable'} and defined $self->{'BitmapImage'};
2383 0         0 $self->CharacterID->pack($stream);
2384 0         0 $stream->set_UI8($self->BitmapFormat);
2385 0         0 $stream->set_UI16($self->BitmapWidth);
2386 0         0 $stream->set_UI16($self->BitmapHeight);
2387 0 0       0 $stream->set_UI8($self->BitmapColorTableSize) if $self->BitmapFormat == 3;
2388 0         0 $self->ZlibBitmapData->pack($stream);
2389             }
2390            
2391 0     0   0 sub decompress {
2392             }
2393            
2394 0     0   0 sub compress {
2395             }
2396            
2397             ##########
2398            
2399             package SWF::Element::Tag::JPEGTables;
2400            
2401             sub _unpack {
2402 0     0   0 my ($self, $stream)=@_;
2403            
2404 0         0 $self->JPEGData->unpack($stream, $self->Length);
2405             }
2406            
2407             sub _pack {
2408 0     0   0 my ($self, $stream)=@_;
2409            
2410 0         0 $self->JPEGData->pack($stream);
2411             }
2412            
2413             #### Buttons ####
2414            
2415             ##########
2416            
2417             package SWF::Element::BUTTONRECORD1;
2418            
2419             sub unpack {
2420 0     0   0 my ($self, $stream)=@_;
2421            
2422 0         0 $self->ButtonStates($stream->get_UI8);
2423 0 0       0 return if $self->ButtonStates == 0;
2424 0         0 $self->CharacterID->unpack($stream);
2425 0         0 $self->PlaceDepth->unpack($stream);
2426 0         0 $self->PlaceMatrix->unpack($stream);
2427             }
2428            
2429             sub pack {
2430 0     0   0 my ($self, $stream)=@_;
2431            
2432 0         0 $stream->set_UI8($self->ButtonStates);
2433 0 0       0 return if $self->ButtonStates == 0;
2434 0         0 $self->CharacterID->pack($stream);
2435 0         0 $self->PlaceDepth->pack($stream);
2436 0         0 $self->PlaceMatrix->pack($stream);
2437             }
2438            
2439             {
2440             my $bit = 0;
2441             for my $f (qw/ButtonStateUp ButtonStateOver ButtonStateDown ButtonStateHitTest/) {
2442             SWF::Element::_create_flag_accessor($f, 'ButtonStates', $bit++);
2443             }
2444             }
2445            
2446             package SWF::Element::BUTTONRECORD2;
2447            
2448             sub unpack {
2449 0     0   0 my ($self, $stream)=@_;
2450            
2451 0         0 $self->SUPER::unpack($stream);
2452 0 0       0 return if $self->ButtonStates == 0;
2453 0         0 $self->ColorTransform->unpack($stream);
2454             }
2455            
2456             sub pack {
2457 0     0   0 my ($self, $stream)=@_;
2458            
2459 0         0 $self->SUPER::pack($stream);
2460 0 0       0 return if $self->ButtonStates == 0;
2461 0         0 $self->ColorTransform->pack($stream);
2462             }
2463            
2464            
2465             ##########
2466            
2467             package SWF::Element::Tag::DefineButton2;
2468            
2469             sub _unpack {
2470 0     0   0 my ($self, $stream)=@_;
2471            
2472 0         0 $self->ButtonID->unpack($stream);
2473 0         0 $self->Flags($stream->get_UI8);
2474 0         0 my $offset=$stream->get_UI16;
2475 0         0 $self->Characters->unpack($stream);
2476 0 0       0 $self->Actions->unpack($stream) if $offset;
2477             }
2478            
2479             sub _pack {
2480 0     0   0 my ($self, $stream)=@_;
2481 0         0 my $actions = $self->Actions;
2482            
2483 0         0 $self->ButtonID->pack($stream);
2484 0         0 $stream->set_UI8($self->Flags);
2485 0         0 my $substream = $stream->sub_stream;
2486 0         0 $self->Characters->pack($substream);
2487 0   0     0 $stream->set_UI16((@$actions>0) && ($substream->tell + 2));
2488 0         0 $substream->flush_stream;
2489 0 0       0 $actions->pack($stream) if (@$actions>0);
2490             }
2491            
2492             SWF::Element::_create_flag_accessor('TrackAsMenu', 'Flags', 0);
2493            
2494             ##########
2495            
2496             package SWF::Element::Array::BUTTONCONDACTIONARRAY;
2497            
2498             sub pack {
2499 0     0   0 my ($self, $stream)=@_;
2500            
2501 0         0 my $last=pop @$self;
2502 0         0 for my $element (@$self) {
2503 0         0 my $tempstream=$stream->sub_stream;
2504 0         0 $element->pack($tempstream);
2505 0         0 $stream->set_UI16($tempstream->tell + 2);
2506 0         0 $tempstream->flush_stream;
2507             }
2508 0         0 $stream->set_UI16(0);
2509 0         0 $last->pack($stream);
2510 0         0 push @$self, $last;
2511             }
2512            
2513             sub unpack {
2514 0     0   0 my ($self, $stream)=@_;
2515 0         0 my ($element, $offset);
2516            
2517 0         0 do {
2518 0         0 $offset=$stream->get_UI16;
2519 0         0 $element=$self->new_element;
2520 0         0 $element->unpack($stream);
2521 0         0 push @$self, $element;
2522             } until $offset==0;
2523             }
2524            
2525             ##########
2526            
2527             package SWF::Element::BUTTONCONDACTION;
2528            
2529             {
2530             my $bit = 0;
2531            
2532             for my $f (qw/IdleToOverUp OverUpToIdle OverUpToOverDown OverDownToOverUp OverDownToOutDown OutDownToOverDown OutDownToIdle IdleToOverDown OverDownToIdle/) {
2533             SWF::Element::_create_flag_accessor("Cond$f", 'Condition', $bit++);
2534             }
2535             SWF::Element::_create_flag_accessor("CondKeyPress", 'Condition', 9, 7);
2536            
2537             }
2538            
2539             ##########
2540            
2541             package SWF::Element::Tag::DefineButtonSound;
2542            
2543             sub _unpack {
2544 0     0   0 my ($self, $stream)=@_;
2545            
2546 0         0 $self->ButtonID->unpack($stream);
2547 0         0 for my $i (0..3) {
2548 0         0 my $bsc = "ButtonSoundChar$i";
2549 0         0 my $bsi = "ButtonSoundInfo$i";
2550            
2551 0         0 $self->$bsc->unpack($stream);
2552 0 0       0 if ($self->$bsc) {
2553 0         0 $self->$bsi->unpack($stream);
2554             }
2555             }
2556             }
2557            
2558             sub _pack {
2559 0     0   0 my ($self, $stream)=@_;
2560            
2561 0         0 $self->ButtonID->pack($stream);
2562 0         0 for my $i (0..3) {
2563 0         0 my $bsc = "ButtonSoundChar$i";
2564 0         0 my $bsi = "ButtonSoundInfo$i";
2565            
2566 0         0 $self->$bsc->pack($stream);
2567 0 0       0 $self->$bsi->pack($stream) if $self->$bsc;
2568             }
2569             }
2570            
2571             #### Texts and Fonts ####
2572             ##########
2573            
2574             package SWF::Element::Array::GLYPHSHAPEARRAY1;
2575            
2576             sub pack {
2577 0     0   0 my ($self, $stream)=@_;
2578 0         0 my $offset = @$self*2+2;
2579            
2580 0         0 $stream->set_UI16($offset);
2581            
2582 0         0 my $tempstream = $stream->sub_stream;
2583            
2584 0         0 for my $element (@$self) {
2585 0         0 $element->pack($tempstream, 1, 0);
2586 0         0 $stream->set_UI16($offset + $tempstream->tell);
2587             }
2588 0         0 $tempstream->flush_stream;
2589             }
2590            
2591             sub unpack {
2592 0     0   0 my ($self, $stream)=@_;
2593 0         0 my $offset=$stream->get_UI16;
2594            
2595 0         0 $stream->get_string($offset-2); # skip offset table.
2596 0         0 for (my $i=0; $i < $offset/2; $i++) {
2597 0         0 my $element = $self->new_element;
2598 0         0 $element->unpack($stream);
2599 0         0 push @$self, $element;
2600             }
2601             }
2602            
2603             ##########
2604            
2605             package SWF::Element::Array::GLYPHSHAPEARRAY2;
2606            
2607             sub pack { # return wide offset flag (true => 32bit, false => 16bit)
2608 0     0   0 my ($self, $stream)=@_;
2609 0         0 my (@offset, $wideoffset);
2610 0         0 my $glyphcount=@$self;
2611            
2612 0         0 $offset[0]=0;
2613 0         0 my $tempstream=$stream->sub_stream;
2614            
2615 0         0 for my $element (@$self) {
2616 0         0 $element->pack($tempstream, 1, 0);
2617 0         0 push @offset, $tempstream->tell; # keep glyph shape's offset.
2618             }
2619            
2620             # Each offset should be added the offset table size.
2621             # If the last offset is more than 65535, offsets are packed in 32bits each.
2622            
2623 0 0       0 if (($glyphcount+1)*2+$offset[-1] >= (1<<16)) {
2624 0         0 $wideoffset=1;
2625 0         0 for my $element (@offset) {
2626 0         0 $stream->set_UI32(($glyphcount+1)*4+$element);
2627             }
2628             } else {
2629 0         0 $wideoffset=0;
2630 0         0 for my $element (@offset) {
2631 0         0 $stream->set_UI16(($glyphcount+1)*2+$element);
2632             }
2633             }
2634 0         0 $tempstream->flush_stream;
2635 0         0 return $wideoffset;
2636             }
2637            
2638             sub unpack {
2639 0     0   0 my ($self, $stream, $wideoffset)=@_;
2640 0         0 my @offset;
2641 0 0   0   0 my $getoffset = ($wideoffset ? sub {$stream->get_UI32} : sub {$stream->get_UI16});
  0         0  
  0         0  
2642 0         0 my $origin = $stream->tell;
2643            
2644 0         0 $offset[0] = &$getoffset;
2645 0 0       0 my $count = $offset[0]>>($wideoffset ? 2:1);
2646            
2647 0         0 for (my $i = 1; $i < $count; $i++) {
2648 0         0 push @offset, &$getoffset;
2649             }
2650 0         0 my $pos = $stream->tell - $origin;
2651 0         0 my $offset = shift @offset;
2652 0 0       0 Carp::croak ref($self).": Font offset table seems to be collapsed." if $pos>$offset;
2653 0 0       0 $stream->get_string($pos-$offset) if $pos<$offset;
2654 0         0 for (my $i = 1; $i < $count; $i++) {
2655 0         0 my $element = $self->new_element;
2656 0         0 $element->unpack($stream);
2657 0         0 push @$self, $element;
2658 0         0 my $pos = $stream->tell - $origin;
2659 0         0 my $offset = shift @offset;
2660 0 0       0 Carp::croak ref($self).": Font shape table seems to be collapsed." if $pos>$offset;
2661 0 0       0 $stream->get_string($pos-$offset) if $pos<$offset;
2662             }
2663             }
2664            
2665            
2666             ##########
2667            
2668             package SWF::Element::Tag::DefineFont2;
2669            
2670             sub _unpack {
2671 0     0   0 my ($self, $stream)=@_;
2672            
2673 0         0 $self->FontID->unpack($stream);
2674 0         0 my $flag = $self->FontFlags($stream->get_UI8);
2675 0         0 $self->LanguageCode($stream->get_UI8);
2676 0         0 $self->FontName->unpack($stream);
2677 0         0 my $glyphcount = $stream->get_UI16;
2678 0 0       0 if ($glyphcount > 0) {
2679 0         0 $self->GlyphShapeTable->unpack($stream, ($flag & 8));
2680 0         0 $self->CodeTable->unpack($stream, $glyphcount, ($flag & 4));
2681             }
2682 0 0       0 if ($flag & 128) {
2683 0         0 $self->FontAscent($stream->get_SI16);
2684 0         0 $self->FontDescent($stream->get_SI16);
2685 0         0 $self->FontLeading($stream->get_SI16);
2686 0         0 $self->FontAdvanceTable->unpack($stream, $glyphcount);
2687 0         0 $self->FontBoundsTable ->unpack($stream, $glyphcount);
2688 0         0 $self->FontKerningTable->unpack($stream, ($flag & 4));
2689             }
2690             }
2691            
2692             sub _pack {
2693 0     0   0 my ($self, $stream)=@_;
2694 0         0 my $glyphcount = @{$self->CodeTable};
  0         0  
2695            
2696 0         0 $self->FontID->pack($stream);
2697 0         0 my $tempstream = $stream->sub_stream;
2698 0   0     0 my $flag = (($self->FontFlags || 0) & 0b01010111);
2699            
2700 0         0 $self->FontName->pack($tempstream);
2701 0         0 $tempstream->set_UI16($glyphcount);
2702 0 0       0 if ($glyphcount > 0){
2703 0 0       0 $self->GlyphShapeTable->pack($tempstream) and ($flag |= 8);
2704 0 0       0 $self->CodeTable->pack($tempstream, $self->FontFlagsWideCodes) and ($flag |= 4);
2705             }
2706 0 0       0 if (defined $self->FontAscent) {
2707 0         0 $flag |= 128;
2708 0         0 $tempstream->set_SI16($self->FontAscent);
2709 0         0 $tempstream->set_SI16($self->FontDescent);
2710 0         0 $tempstream->set_SI16($self->FontLeading);
2711 0         0 $self->FontAdvanceTable->pack($tempstream);
2712 0         0 $self->FontBoundsTable->pack($tempstream);
2713 0         0 $self->FontKerningTable->pack($tempstream, ($flag & 4));
2714             }
2715 0         0 $stream->set_UI8($flag);
2716 0         0 $stream->set_UI8($self->LanguageCode);
2717 0         0 $tempstream->flush_stream;
2718             }
2719            
2720             {
2721             my $bit = 0;
2722             for my $f (qw/ Bold Italic WideCodes WideOffsets ANSI SmallText ShiftJIS HasLayout /) {
2723             SWF::Element::_create_flag_accessor("FontFlags$f", 'FontFlags', $bit++);
2724             }
2725             }
2726            
2727             ##########
2728            
2729             package SWF::Element::Array::CODETABLE;
2730            
2731             sub pack {
2732 0     0   0 my ($self, $stream, $widecode)=@_;
2733            
2734 0         0 for my $element (@$self) {
2735 0 0       0 if ($element > 255) {
2736 0         0 $widecode = 1;
2737 0         0 last;
2738             }
2739             }
2740 0 0       0 if ($widecode) {
2741 0         0 for my $element (@$self) {
2742 0         0 $stream->set_UI16($element);
2743             }
2744             } else {
2745 0         0 for my $element (@$self) {
2746 0         0 $stream->set_UI8($element);
2747             }
2748             }
2749 0         0 $widecode;
2750             }
2751            
2752             sub unpack {
2753 0     0   0 my ($self, $stream, $glyphcount, $widecode)=@_;
2754 0         0 my ($templete);
2755 0 0       0 if ($widecode) {
2756 0         0 $glyphcount*=2;
2757 0         0 $templete='v*';
2758             } else {
2759 0         0 $templete='C*';
2760             }
2761            
2762 0         0 @$self=unpack($templete,$stream->get_string($glyphcount));
2763             }
2764            
2765             ##########
2766            
2767             package SWF::Element::Array::FONTADVANCETABLE;
2768            
2769             sub pack {
2770 0     0   0 my ($self, $stream)=@_;
2771            
2772 0         0 for my $element (@$self) {
2773 0         0 $stream->set_SI16($element);
2774             }
2775             }
2776            
2777             sub unpack {
2778 0     0   0 my ($self, $stream, $glyphcount)=@_;
2779            
2780 0         0 while (--$glyphcount >=0) {
2781 0         0 push @$self, $stream->get_SI16;
2782             }
2783             }
2784            
2785             ##########
2786            
2787             package SWF::Element::Array::FONTBOUNDSTABLE;
2788            
2789             sub unpack {
2790 0     0   0 my ($self, $stream, $glyphcount)=@_;
2791            
2792 0         0 while (--$glyphcount >=0) {
2793 0         0 my $element = $self->new_element;
2794 0         0 $element->unpack($stream);
2795 0         0 push @$self, $element;
2796             }
2797             }
2798            
2799             ##########
2800            
2801             package SWF::Element::FONTKERNINGTABLE;
2802            
2803             @SWF::Element::FONTKERNINGTABLE::ISA = ('SWF::Element');
2804            
2805             sub new {
2806 0     0   0 my $class = shift;
2807 0         0 my $self = {};
2808            
2809 0   0     0 $class=ref($class)||$class;
2810            
2811 0         0 bless $self, $class;
2812 0 0       0 $self->configure(@_) if @_;
2813 0         0 $self;
2814             }
2815            
2816             sub unpack {
2817 0     0   0 my ($self, $stream, $widecode)=@_;
2818 0         0 my $count=$stream->get_UI16;
2819 0 0   0   0 my $getcode=($widecode ? sub {$stream->get_UI16} : sub {$stream->get_UI8});
  0         0  
  0         0  
2820 0         0 %$self=();
2821 0         0 while (--$count>=0) {
2822 0         0 my $code1=&$getcode;
2823 0         0 my $code2=&$getcode;
2824 0         0 $self->{"$code1-$code2"}=$stream->get_SI16;
2825             }
2826             }
2827            
2828             sub pack {
2829 0     0   0 my ($self, $stream, $widecode)=@_;
2830 0 0   0   0 my $setcode=($widecode ? sub {$stream->set_UI16(shift)} : sub {$stream->set_UI8(shift)});
  0         0  
  0         0  
2831 0         0 my ($k, $v);
2832            
2833 0         0 $stream->set_UI16(scalar(keys(%$self)));
2834 0         0 while (($k, $v)=each(%$self)) {
2835 0         0 my ($code1, $code2)=split(/-/,$k);
2836 0         0 &$setcode($code1);
2837 0         0 &$setcode($code2);
2838 0         0 $stream->set_SI16($v);
2839             }
2840             }
2841            
2842             sub configure {
2843 0     0   0 my ($self, @param)=@_;
2844            
2845 0 0       0 if (@param==0) {
    0          
2846 0         0 return map {$_, $self->{$_}} grep {defined $self->{$_}} keys(%$self);
  0         0  
  0         0  
2847             } elsif (@param==1) {
2848 0         0 my $k=$param[0];
2849 0 0       0 return undef unless exists $self->{$k};
2850 0         0 return $self->{$k};
2851             } else {
2852 0         0 my %param=@param;
2853 0         0 my ($key, $value);
2854 0         0 while (($key, $value) = each %param) {
2855 0 0       0 next if $key!~/^\d+-\d+$/;
2856 0         0 $self->{$key}=$value;
2857             }
2858             }
2859             }
2860            
2861             sub dumper {
2862 0     0   0 my ($self, $outputsub, $indent)=@_;
2863 0         0 my ($k, $v);
2864            
2865 0   0     0 $indent ||= 0;
2866 0   0     0 $outputsub||=\&SWF::Element::_default_output;
2867            
2868 0         0 &$outputsub(ref($self)."->new(\n", 0);
2869 0         0 while (($k, $v) = each %$self) {
2870 0         0 &$outputsub("'$k' => $v,\n", $indent + 1);
2871             }
2872 0         0 &$outputsub(")", $indent);
2873             }
2874            
2875             sub defined {
2876 0     0   0 keys %{shift()} > 0;
  0         0  
2877             }
2878            
2879             ##########
2880            
2881             package SWF::Element::Tag::DefineFontInfo;
2882            
2883             sub _unpack {
2884 0     0   0 my ($self, $stream)=@_;
2885            
2886 0         0 my $start = $stream->tell;
2887 0         0 $self->FontID ->unpack($stream);
2888 0         0 $self->FontName ->unpack($stream);
2889 0         0 my $widecode = $self->FontFlags($stream->get_UI8) & 1;
2890 0         0 my $glyphcount = $self->Length - ($stream->tell - $start);
2891 0 0       0 $glyphcount >>= 1 if $widecode;
2892 0         0 $self->CodeTable->unpack($stream, $glyphcount, $widecode);
2893             }
2894            
2895             sub _pack {
2896 0     0   0 my ($self, $stream)=@_;
2897            
2898 0         0 $self->FontID ->pack($stream);
2899 0         0 $self->FontName ->pack($stream);
2900 0         0 my $substream = $stream->sub_stream;
2901 0         0 my $flag = $self->FontFlags & 0b11110;
2902 0 0       0 $self->CodeTable->pack($substream) and ($flag |= 1);
2903            
2904 0         0 $stream->set_UI8($flag);
2905 0         0 $substream->flush_stream;
2906             }
2907            
2908             {
2909             my $bit = 0;
2910             for my $f (qw/ WideCodes Bold Italic ANSI ShiftJIS SmallText/) {
2911             SWF::Element::_create_flag_accessor("FontFlags$f", 'FontFlags', $bit++);
2912             }
2913             }
2914            
2915             ##########
2916            
2917             package SWF::Element::Tag::DefineFontInfo2;
2918            
2919             sub _unpack {
2920 0     0   0 my ($self, $stream)=@_;
2921            
2922 0         0 my $start = $stream->tell;
2923 0         0 $self->FontID ->unpack($stream);
2924 0         0 $self->FontName ->unpack($stream);
2925 0         0 my $widecode = $self->FontFlags($stream->get_UI8) & 1;
2926 0         0 $self->LanguageCode($stream->get_UI8);
2927 0         0 my $glyphcount = $self->Length - ($stream->tell - $start);
2928 0 0       0 $glyphcount >>= 1 if $widecode;
2929 0         0 $self->CodeTable->unpack($stream, $glyphcount, $widecode);
2930             }
2931            
2932             sub _pack {
2933 0     0   0 my ($self, $stream)=@_;
2934            
2935 0         0 $self->FontID ->pack($stream);
2936 0         0 $self->FontName ->pack($stream);
2937 0         0 my $substream = $stream->sub_stream;
2938 0         0 my $flag = ($self->FontFlags & 0b11100111 | 1);
2939 0         0 $self->CodeTable->pack($substream, 1);
2940            
2941 0         0 $stream->set_UI8($flag);
2942 0         0 $stream->set_UI8($self->LanguageCode);
2943 0         0 $substream->flush_stream;
2944             }
2945            
2946            
2947             ##########
2948            
2949             package SWF::Element::Array::TEXTRECORDARRAY1;
2950            
2951             sub pack {
2952 0     0   0 my ($self, $stream)=@_;
2953 0         0 my ($nglyphmax, $nglyphbits, $nadvancemax, $nadvancebits, $g, $a) = (0) x 6;
2954            
2955 0         0 for my $element (@$self) {
2956 0         0 for my $entry (@{$element->GlyphEntries}) {
  0         0  
2957 0         0 $g=$entry->GlyphIndex;
2958 0         0 $a=$entry->GlyphAdvance;
2959 0 0       0 $a=~$a if $a<0;
2960 0 0       0 $nglyphmax=$g if $g>$nglyphmax;
2961 0 0       0 $nadvancemax=$a if $a>$nadvancemax;
2962             }
2963             }
2964 0         0 $nglyphbits++ while ($nglyphmax>=(1<<$nglyphbits));
2965 0         0 $nadvancebits++ while ($nadvancemax>=(1<<$nadvancebits));
2966 0         0 $nadvancebits++; # for sign bit.
2967            
2968 0         0 $stream->set_UI8($nglyphbits);
2969 0         0 $stream->set_UI8($nadvancebits);
2970            
2971 0         0 for my $element (@$self) {
2972 0         0 $element->pack($stream, $nglyphbits, $nadvancebits);
2973             }
2974 0         0 $self->last($stream);
2975             }
2976            
2977             sub unpack {
2978 0     0   0 my ($self, $stream)=@_;
2979 0         0 my ($nglyphbits, $nadvancebits);
2980 0         0 my ($flags);
2981            
2982 0         0 $nglyphbits=$stream->get_UI8;
2983 0         0 $nadvancebits=$stream->get_UI8;
2984             {
2985 0         0 my $element = $self->new_element;
  0         0  
2986 0         0 $element->unpack($stream, $nglyphbits, $nadvancebits);
2987 0 0       0 last if $self->is_last($element);
2988 0         0 push @$self, $element;
2989 0         0 redo;
2990             }
2991             }
2992            
2993             ##########
2994            
2995             package SWF::Element::TEXTRECORD1;
2996            
2997             sub unpack {
2998 0     0   0 my $self = shift;
2999 0         0 my $stream = shift;
3000            
3001 0         0 my $flags = $stream->get_UI8;
3002 0 0       0 if ($flags == 0) {
3003 0         0 return bless $self, 'SWF::Element::TEXTRECORD::End';
3004             }
3005 0 0       0 $self->FontID ->unpack($stream) if ($flags & 8);
3006 0 0       0 $self->TextColor->unpack($stream) if ($flags & 4);
3007 0 0       0 $self->XOffset($stream->get_SI16) if ($flags & 1);
3008 0 0       0 $self->YOffset($stream->get_SI16) if ($flags & 2);
3009 0 0       0 $self->TextHeight($stream->get_UI16) if ($flags & 8);
3010 0         0 $self->GlyphEntries->unpack($stream, @_);
3011             }
3012            
3013             sub pack {
3014 0     0   0 my $self = shift;
3015 0         0 my $stream = shift;
3016 0         0 my ($flags)=0x80;
3017            
3018 0 0 0     0 $flags|=8 if $self->FontID->defined or defined $self->TextHeight;
3019 0 0       0 $flags|=4 if $self->TextColor->defined;
3020 0 0       0 $flags|=1 if defined $self->XOffset;
3021 0 0       0 $flags|=2 if defined $self->YOffset;
3022 0         0 $stream->set_UI8($flags);
3023            
3024 0 0       0 $self->FontID->pack($stream) if ($flags & 8);
3025 0 0       0 $self->TextColor->pack($stream) if ($flags & 4);
3026 0 0       0 $stream->set_SI16($self->XOffset) if ($flags & 1);
3027 0 0       0 $stream->set_SI16($self->YOffset) if ($flags & 2);
3028 0 0       0 $stream->set_UI16($self->TextHeight) if ($flags & 8);
3029 0         0 $self->GlyphEntries->pack($stream, @_);
3030             }
3031            
3032             ##########
3033            
3034             package SWF::Element::GLYPHENTRY;
3035            
3036             sub unpack {
3037 0     0   0 my ($self, $stream, $nglyphbits, $nadvancebits)=@_;
3038            
3039 0         0 $self->GlyphIndex($stream->get_bits($nglyphbits));
3040 0         0 $self->GlyphAdvance($stream->get_sbits($nadvancebits));
3041             }
3042            
3043             sub pack {
3044 0     0   0 my ($self, $stream, $nglyphbits, $nadvancebits)=@_;
3045            
3046 0         0 $stream->set_bits($self->GlyphIndex, $nglyphbits);
3047 0         0 $stream->set_sbits($self->GlyphAdvance, $nadvancebits);
3048             }
3049            
3050             ##########
3051            
3052             package SWF::Element::TEXTRECORD1::TYPE1;
3053            
3054             =pod obsolete
3055            
3056             sub unpack {
3057             my ($self, $stream, $flags)=@_;
3058            
3059             $self->FontID ->unpack($stream) if ($flags & 8);
3060             $self->TextColor->unpack($stream) if ($flags & 4);
3061             $self->XOffset($stream->get_SI16) if ($flags & 1);
3062             $self->YOffset($stream->get_SI16) if ($flags & 2);
3063             $self->TextHeight($stream->get_UI16) if ($flags & 8);
3064             }
3065            
3066             =cut
3067            
3068             sub pack {
3069 0     0   0 my ($self, $stream)=@_;
3070 0         0 my ($flags)=0x80;
3071            
3072 0 0 0     0 $flags|=8 if $self->FontID->defined or defined $self->TextHeight;
3073 0 0       0 $flags|=4 if $self->TextColor->defined;
3074 0 0       0 $flags|=1 if defined $self->XOffset;
3075 0 0       0 $flags|=2 if defined $self->YOffset;
3076 0         0 $stream->set_UI8($flags);
3077            
3078 0 0       0 $self->FontID->pack($stream) if ($flags & 8);
3079 0 0       0 $self->TextColor->pack($stream) if ($flags & 4);
3080 0 0       0 $stream->set_SI16($self->XOffset) if ($flags & 1);
3081 0 0       0 $stream->set_SI16($self->YOffset) if ($flags & 2);
3082 0 0       0 $stream->set_UI16($self->TextHeight) if ($flags & 8);
3083             }
3084            
3085            
3086             ##########
3087            
3088             package SWF::Element::Tag::DefineEditText;
3089            
3090             sub _unpack {
3091 0     0   0 my ($self, $stream)=@_;
3092            
3093 0         0 $self->CharacterID->unpack($stream);
3094 0         0 $self->Bounds->unpack($stream);
3095 0         0 my $flag = $self->Flags($stream->get_UI16);
3096            
3097 0 0       0 if ($flag & 1) {
3098 0         0 $self->FontID->unpack($stream);
3099 0         0 $self->FontHeight($stream->get_UI16);
3100             }
3101 0 0       0 $self->TextColor->unpack($stream) if $flag & 4;
3102 0 0       0 $self->MaxLength($stream->get_UI16) if $flag & 2;
3103            
3104 0 0       0 if ($flag & (1<<13)) {
3105 0         0 $self->Align($stream->get_UI8);
3106 0         0 for my $element (qw/LeftMargin RightMargin Indent Leading/) {
3107 0         0 $self->$element($stream->get_UI16);
3108             }
3109             }
3110 0         0 $self->VariableName->unpack($stream);
3111 0 0       0 $self->InitialText->unpack($stream) if $flag & 128;
3112             }
3113            
3114             sub _pack {
3115 0     0   0 my ($self, $stream)=@_;
3116            
3117 0         0 my $flag = $self->Flags & 0b101101101111000;
3118 0   0     0 $flag |= ($self->FontID->defined or defined $self->FontHeight) |
      0        
3119             defined ($self->MaxLength) << 1 |
3120             ($self->TextColor->defined) << 2 |
3121             ($self->InitialText->defined) << 7 |
3122             (defined $self->Align
3123             or defined $self->LeftMargin
3124             or defined $self->RightMargin
3125             or defined $self->Indent
3126             or defined $self->Leading) << 13;
3127            
3128 0         0 $self->CharacterID->pack($stream);
3129 0         0 $self->Bounds->pack($stream);
3130 0         0 $stream->set_UI16($flag);
3131            
3132 0 0       0 if ($flag & 1) {
3133 0         0 $self->FontID->pack($stream);
3134 0         0 $stream->set_UI16($self->FontHeight);
3135             }
3136 0 0       0 $self->TextColor->pack($stream) if $flag & 4;
3137 0 0       0 $stream->set_UI16($self->MaxLength) if $flag & 2;
3138 0 0       0 if ($flag & (1<<13)) {
3139 0         0 $stream->set_UI8($self->Align);
3140 0         0 for my $element (qw/LeftMargin RightMargin Indent Leading/) {
3141 0         0 $stream->set_UI16($self->$element);
3142             }
3143             }
3144 0         0 $self->VariableName->pack($stream);
3145 0 0       0 $self->InitialText->pack($stream) if $flag & 128;
3146             }
3147            
3148             {
3149             my $bit = 0;
3150             for my $f (qw / HasFont HasMaxLength HasTextColor ReadOnly Password Multiline WordWrap HasText UseOutlines HTML Reserved Border NoSelect HasLayout AutoSize / ) {
3151             SWF::Element::_create_flag_accessor($f, 'Flags', $bit++);
3152             }
3153             }
3154            
3155             #### Sounds ####
3156             ##########
3157            
3158             package SWF::Element::SOUNDINFO;
3159            
3160             sub unpack {
3161 0     0   0 my ($self, $stream)=@_;
3162 0         0 my $flags=$stream->get_UI8;
3163            
3164 0         0 $self->SyncFlags($flags);
3165            
3166 0 0       0 $self->InPoint($stream->get_UI32) if ($flags & 1);
3167 0 0       0 $self->OutPoint($stream->get_UI32) if ($flags & 2);
3168 0 0       0 $self->LoopCount($stream->get_UI16) if ($flags & 4);
3169 0 0       0 $self->EnvelopeRecords->unpack($stream) if ($flags & 8);
3170             }
3171            
3172             sub pack {
3173 0     0   0 my ($self, $stream)=@_;
3174 0         0 my $flags=$self->SyncFlags |
3175             $self->EnvelopeRecords->defined << 3 |
3176             defined($self->LoopCount) << 2 |
3177             defined($self->OutPoint) << 1 |
3178             defined($self->InPoint);
3179 0         0 $stream->set_UI8($flags);
3180            
3181 0 0       0 $stream->set_UI32($self->InPoint) if ($flags & 1);
3182 0 0       0 $stream->set_UI32($self->OutPoint) if ($flags & 2);
3183 0 0       0 $stream->set_UI16($self->LoopCount) if ($flags & 4);
3184 0 0       0 $self->EnvelopeRecords->pack($stream) if ($flags & 8);
3185             }
3186            
3187             {
3188             my $bit = 0;
3189             for my $f (qw/ HasInPoint HasOutPoint HasLoops HasEnvelope SyncNoMultiple SyncStop /) {
3190             SWF::Element::_create_flag_accessor($f, 'SyncFlags', $bit++);
3191             }
3192             }
3193            
3194             ##########
3195            
3196             package SWF::Element::Tag::DefineSound;
3197            
3198             sub _unpack {
3199 0     0   0 my ($self, $stream)=@_;
3200            
3201 0         0 $self->SoundID->unpack($stream);
3202 0         0 $self->Flags($stream->get_UI8);
3203 0         0 $self->SoundSampleCount($stream->get_UI32);
3204 0         0 $self->SoundData->unpack($stream, $self->Length - 7);
3205             }
3206            
3207             sub _pack {
3208 0     0   0 my ($self, $stream)=@_;
3209            
3210 0         0 $self->SoundID->pack($stream);
3211 0         0 $stream->set_UI8($self->Flags);
3212 0         0 $stream->set_UI32($self->SoundSampleCount);
3213 0         0 $self->SoundData->pack($stream);
3214             }
3215            
3216             SWF::Element::_create_flag_accessor("SoundFormat", 'Flags', 4, 4);
3217             SWF::Element::_create_flag_accessor("SoundRate", 'Flags', 2, 2);
3218             SWF::Element::_create_flag_accessor("SoundSize", 'Flags', 1, 1);
3219             SWF::Element::_create_flag_accessor("SoundType", 'Flags', 0, 1);
3220            
3221             ##########
3222            
3223             package SWF::Element::Tag::SoundStreamBlock;
3224            
3225             sub _unpack {
3226 0     0   0 my ($self, $stream)=@_;
3227            
3228 0         0 $self->StreamSoundData->unpack($stream, $self->Length);
3229             }
3230            
3231             sub _pack {
3232 0     0   0 my ($self, $stream)=@_;
3233            
3234 0         0 $self->StreamSoundData->pack($stream);
3235             }
3236            
3237             ##########
3238            
3239             package SWF::Element::Tag::SoundStreamHead;
3240            
3241             sub _unpack {
3242 0     0   0 my ($self, $stream)=@_;
3243            
3244 0         0 $self->Flags($stream->get_UI16);
3245 0         0 $self->StreamSoundSampleCount($stream->get_UI16);
3246 0 0       0 $self->LatencySeek($stream->get_SI16) if $self->Length == 6;
3247             }
3248            
3249             sub _pack {
3250 0     0   0 my ($self, $stream)=@_;
3251            
3252 0         0 $stream->set_UI16($self->Flags);
3253 0         0 $stream->set_UI16($self->StreamSoundSampleCount);
3254 0 0 0     0 $stream->set_SI16($self->LatencySeek) if $self->StreamSoundCompression == 2 and defined($self->LatencySeek);
3255             }
3256            
3257            
3258             SWF::Element::_create_flag_accessor('StreamSoundCompression', 'Flags',12, 4);
3259             SWF::Element::_create_flag_accessor('StreamSoundRate', 'Flags', 10, 2);
3260             SWF::Element::_create_flag_accessor('StreamSoundSize', 'Flags', 9, 1);
3261             SWF::Element::_create_flag_accessor('StreamSoundType', 'Flags', 8, 1);
3262             SWF::Element::_create_flag_accessor('PlaybackSoundRate', 'Flags', 2, 2);
3263             SWF::Element::_create_flag_accessor('PlaybackSoundSize', 'Flags', 1, 1);
3264             SWF::Element::_create_flag_accessor('PlaybackSoundType', 'Flags', 0, 1);
3265            
3266             #### Sprites ####
3267             ##########
3268            
3269             package SWF::Element::TAGSTREAM;
3270            
3271 1     1   2841 use SWF::Parser;
  1         2  
  1         2818  
3272            
3273             sub new {
3274 0     0   0 my $self;
3275 0         0 bless \$self, shift;
3276             }
3277            
3278             sub configure {
3279 0     0   0 my ($self, $data, $version) = @_;
3280            
3281 0         0 $$self = SWF::BinStream::Read->new($data, undef, $version);
3282 0         0 $self;
3283             }
3284            
3285             sub dumper {
3286 0     0   0 my ($self, $outputsub)=@_;
3287            
3288 0   0     0 $outputsub||=\&SWF::Element::_default_output;
3289            
3290 0         0 &$outputsub('undef', 0);
3291             }
3292            
3293             sub defined {
3294 0     0   0 defined ${+shift};
  0         0  
3295             }
3296            
3297             sub parse {
3298 0     0   0 my ($self, $p, $callback) = @_;
3299            
3300 0 0 0     0 if (ref($p) eq 'CODE' and !defined $callback) {
    0 0        
3301 0         0 $callback = $p;
3302             } elsif (lc($p) ne 'callback' or ref($callback) ne 'CODE') {
3303 0         0 Carp::croak "Callback subroutine is needed to parse tags of sprite";
3304             }
3305 0         0 my $parser = SWF::Parser->new('tag-callback' => $callback, stream => $$self, header => 'no');
3306 0         0 $parser->parse;
3307             }
3308            
3309             ##########
3310            
3311             package SWF::Element::Tag::DefineSprite;
3312            
3313             sub _unpack {
3314 0     0   0 my ($self, $stream)=@_;
3315            
3316 0         0 $self->SpriteID->unpack($stream);
3317 0         0 $self->FrameCount($stream->get_UI16);
3318 0         0 $self->ControlTags->unpack($stream);
3319             }
3320            
3321             sub shallow_unpack {
3322 0     0   0 my ($self, $stream) = @_;
3323            
3324 0         0 $self->SpriteID->unpack($stream);
3325 0         0 $self->FrameCount($stream->get_UI16);
3326 0         0 $self->TagStream($stream->get_string($self->Length - 4), $stream->Version);
3327             }
3328            
3329             sub _pack {
3330 0     0   0 my ($self, $stream)=@_;
3331            
3332 0         0 $self->SpriteID->pack($stream);
3333 0         0 my $tempstream = $stream->sub_stream;
3334 0         0 for my $tag (@{$self->ControlTags}) {
  0         0  
3335 0 0       0 unless ($tag->is_tagtype('ValidInSprite')) {
3336 0         0 Carp::carp $tag->tag_name." is invalid tag in DefineSprite " ;
3337 0         0 next;
3338             }
3339 0         0 $tag->pack($tempstream);
3340             }
3341 0         0 $stream->set_UI16($tempstream->{_framecount});
3342 0         0 $tempstream->flush_stream;
3343             }
3344            
3345             #### Display List ####
3346             ##########
3347            
3348             package SWF::Element::Tag::PlaceObject;
3349            
3350             sub _unpack {
3351 0     0   0 my ($self, $stream)=@_;
3352            
3353 0         0 my $start = $stream->tell;
3354            
3355 0         0 $self->CharacterID->unpack($stream);
3356 0         0 $self->Depth->unpack($stream);
3357 0         0 $self->Matrix->unpack($stream);
3358 0 0       0 if ($stream->tell < $start + $self->Length) {
3359 0         0 $self->ColorTransform->unpack($stream);
3360             }
3361             }
3362            
3363             sub _pack {
3364 0     0   0 my ($self, $stream)=@_;
3365            
3366 0         0 $self->CharacterID->pack($stream);
3367 0         0 $self->Depth->pack($stream);
3368 0         0 $self->Matrix->pack($stream);
3369 0 0       0 $self->ColorTransform->pack($stream) if $self->ColorTransform->defined;
3370             }
3371            
3372             ##########
3373            
3374             package SWF::Element::Tag::PlaceObject2;
3375            
3376             sub _unpack {
3377 1     1   3 my ($self, $stream)=@_;
3378            
3379 1         6 my $flag = $self->Flags($stream->get_UI8);
3380 1         6 $self->Depth ->unpack($stream);
3381 1 50       10 $self->CharacterID ->unpack($stream) if $flag & 2;
3382 1 50       7 $self->Matrix ->unpack($stream) if $flag & 4;
3383 1 50       4 $self->ColorTransform->unpack($stream) if $flag & 8;
3384 1 50       6 $self->Ratio($stream->get_UI16) if $flag & 16;
3385 1 50       6 $self->Name ->unpack($stream) if $flag & 32;
3386 1 50       4 $self->ClipDepth ->unpack($stream) if $flag & 64;
3387 1 50       5 if ($flag & 128) {
3388 0         0 $stream->get_UI16; # skip reserved.
3389 0 0       0 if ($stream->Version >= 6) { # skip clipaction flag
3390 0         0 $stream->get_UI32;
3391             # $stream->get_UI16;
3392             } else {
3393 0         0 $stream->get_UI16;
3394             }
3395 0         0 $self->ClipActions->unpack($stream);
3396             }
3397             }
3398            
3399             sub _pack {
3400 1     1   4 my ($self, $stream)=@_;
3401 1         20 my $flag = ($self->PlaceFlagMove |
3402             ((my $cid = $self->CharacterID)->defined) << 1 |
3403             ((my $matrix = $self->Matrix) ->defined) << 2 |
3404             ((my $ctfm = $self->ColorTransform)->defined) << 3 |
3405             (defined (my $ratio = $self->Ratio) << 4) |
3406             ((my $name = $self->Name)->defined) << 5 |
3407             ((my $cdepth = $self->ClipDepth)->defined) << 6 |
3408             ((my $caction = $self->ClipActions)->defined) << 7) ;
3409 1         7 $stream->set_UI8($flag);
3410 1         4 $self->Depth->pack($stream);
3411 1 50       7 $cid ->pack($stream) if $flag & 2;
3412 1 50       8 $matrix->pack($stream) if $flag & 4;
3413 1 50       17 $ctfm ->pack($stream) if $flag & 8;
3414 1 50       4 $stream->set_UI16($ratio) if $flag & 16;
3415 1 50       6 $name ->pack($stream) if $flag & 32;
3416 1 50       4 $cdepth->pack($stream) if $flag & 64;
3417 1 50       5 if ($flag & 128) {
3418 0         0 $stream->set_UI16(0); # Reserved.
3419 0         0 my $f = 0;
3420 0         0 for my $e (@{$caction}) {
  0         0  
3421 0         0 $f |= $e->EventFlags;
3422             }
3423 0 0       0 if ($stream->Version >= 6) {
3424 0         0 $stream->set_UI32($f);
3425             } else {
3426 0         0 $stream->set_UI16($f);
3427             }
3428 0         0 $caction->pack($stream);
3429             }
3430             }
3431            
3432             sub lookahead_CharacterID {
3433 0     0   0 my ($self, $stream) = @_;
3434 0         0 $self->lookahead_Flags($stream);
3435 0 0       0 $self->CharacterID($stream->lookahead_UI16(2)) if $self->PlaceFlagHasCharacter;
3436             };
3437            
3438             {
3439             my $bit = 0;
3440             for my $f (qw/ Move HasCharacter HasMatrix HasColorTransform HasRatio HasName HasClipDepth HasClipActions /) {
3441             SWF::Element::_create_flag_accessor("PlaceFlag$f", 'Flags', $bit++);
3442             }
3443             }
3444            
3445             ##########
3446            
3447             package SWF::Element::Tag::ShowFrame;
3448            
3449             sub pack {
3450 1     1   2 my ($self, $stream) = @_;
3451            
3452 1         8 $self->SUPER::pack($stream);
3453 1         10 $stream->{_framecount}++;
3454             }
3455            
3456             package SWF::Element::Tag::ShowFrame::Packed;
3457            
3458             sub pack {
3459 0     0   0 my ($self, $stream) = @_;
3460            
3461 0         0 $self->SUPER::pack($stream);
3462 0         0 $stream->{_framecount}++;
3463             }
3464            
3465             #### Controls ####
3466             ##########
3467            
3468             package SWF::Element::Tag::Protect;
3469            
3470             sub _unpack {
3471 0     0   0 my ($self, $stream) = @_;
3472            
3473 0         0 $self->Reserved($stream->get_UI16);
3474 0         0 $self->Password->unpack($stream);
3475             }
3476            
3477             sub _pack {
3478 0     0   0 my ($self, $stream) = @_;
3479            
3480 0 0       0 $self->Password->pack($stream) if $self->Password->defined;
3481             }
3482            
3483             ##########
3484            
3485             package SWF::Element::Tag::FrameLabel;
3486            
3487             sub _unpack {
3488 1     1   3 my ($self, $stream) = @_;
3489            
3490 1         5 $self->Name->unpack($stream);
3491 1 50       5 if ($self->Length > length($self->Name->value)+1) {
3492 0         0 $self->NamedAnchorFlag($stream->get_UI8);
3493             }
3494             }
3495            
3496             sub _pack {
3497 1     1   2 my ($self, $stream) = @_;
3498            
3499 1         4 $self->Name->pack($stream);
3500 1 50       5 $stream->set_UI8($self->NamedAnchorFlag) if $self->NamedAnchorFlag;
3501             }
3502            
3503             #### Actions ####
3504             ##########
3505            
3506             package SWF::Element::ACTIONRECORD;
3507            
3508            
3509             our %actiontagtonum=(
3510             ActionEnd => 0x00,
3511             ActionNextFrame => 0x04,
3512             ActionPrevFrame => 0x05,
3513             ActionPlay => 0x06,
3514             ActionStop => 0x07,
3515             ActionToggleQuality => 0x08,
3516             ActionStopSounds => 0x09,
3517             ActionAdd => 0x0A,
3518             ActionSubtract => 0x0B,
3519             ActionMultiply => 0x0C,
3520             ActionDivide => 0x0D,
3521             ActionEquals => 0x0E,
3522             ActionLess => 0x0F,
3523             ActionAnd => 0x10,
3524             ActionOr => 0x11,
3525             ActionNot => 0x12,
3526             ActionStringEquals => 0x13,
3527             ActionStringLength => 0x14,
3528             ActionStringExtract => 0x15,
3529             ActionPop => 0x17,
3530             ActionToInteger => 0x18,
3531             ActionGetVariable => 0x1C,
3532             ActionSetVariable => 0x1D,
3533             ActionSetTarget2 => 0x20,
3534             ActionStringAdd => 0x21,
3535             ActionGetProperty => 0x22,
3536             ActionSetProperty => 0x23,
3537             ActionCloneSprite => 0x24,
3538             ActionRemoveSprite => 0x25,
3539             ActionTrace => 0x26,
3540             ActionStartDrag => 0x27,
3541             ActionEndDrag => 0x28,
3542             ActionStringLess => 0x29,
3543             ActionThrow => 0x2a,
3544             ActionCastOp => 0x2b,
3545             ActionImplementsOp => 0x2c,
3546             ActionFSCommand2 => 0x2d,
3547             ActionRandomNumber => 0x30,
3548             ActionMBStringLength => 0x31,
3549             ActionCharToAscii => 0x32,
3550             ActionAsciiToChar => 0x33,
3551             ActionGetTime => 0x34,
3552             ActionMBStringExtract => 0x35,
3553             ActionMBCharToAscii => 0x36,
3554             ActionMBAsciiToChar => 0x37,
3555             ActionDelete => 0x3a,
3556             ActionDelete2 => 0x3b,
3557             ActionDefineLocal => 0x3c,
3558             ActionCallFunction => 0x3d,
3559             ActionReturn => 0x3e,
3560             ActionModulo => 0x3f,
3561             ActionNewObject => 0x40,
3562             ActionDefineLocal2 => 0x41,
3563             ActionInitArray => 0x42,
3564             ActionInitObject => 0x43,
3565             ActionTypeOf => 0x44,
3566             ActionTargetPath => 0x45,
3567             ActionEnumerate => 0x46,
3568             ActionAdd2 => 0x47,
3569             ActionLess2 => 0x48,
3570             ActionEquals2 => 0x49,
3571             ActionToNumber => 0x4a,
3572             ActionToString => 0x4b,
3573             ActionPushDuplicate => 0x4C,
3574             ActionStackSwap => 0x4d,
3575             ActionGetMember => 0x4e,
3576             ActionSetMember => 0x4f,
3577             ActionIncrement => 0x50,
3578             ActionDecrement => 0x51,
3579             ActionCallMethod => 0x52,
3580             ActionNewMethod => 0x53,
3581             ActionInstanceOf => 0x54,
3582             ActionEnumerate2 => 0x55,
3583             ActionBitAnd => 0x60,
3584             ActionBitOr => 0x61,
3585             ActionBitXor => 0x62,
3586             ActionBitLShift => 0x63,
3587             ActionBitRShift => 0x64,
3588             ActionBitURShift => 0x65,
3589             ActionStrictEquals => 0x66,
3590             ActionGreater => 0x67,
3591             ActionStringGreater => 0x68,
3592             ActionExtends => 0x69,
3593             # ActionCall => 0x9e,
3594             );
3595            
3596             our %actionnumtotag= reverse %actiontagtonum;
3597            
3598             sub new {
3599 0     0   0 my ($class, @headerdata)=@_;
3600 0 0       0 my %headerdata = ref($headerdata[0]) eq 'ARRAY' ? @{$headerdata[0]} : @headerdata;
  0         0  
3601 0         0 my $self = [];
3602 0         0 my $tag = $headerdata{Tag};
3603            
3604 0 0 0     0 if (defined($tag) and $tag !~/^\d+$/) {
3605 0 0       0 $tag = "Action$tag" unless $tag =~ /^Action/;
3606 0         0 my $tag1 = $actiontagtonum{$tag};
3607 0 0       0 Carp::croak "ACTIONRECORD '$tag' is not defined." unless defined $tag1;
3608 0         0 $tag = $tag1;
3609             }
3610 0         0 delete $headerdata{Tag};
3611 0   0     0 $class=ref($class)||$class;
3612 0         0 bless $self, $class;
3613 0 0       0 if (defined $tag) {
3614 0         0 $self->Tag($tag);
3615 0         0 bless $self, _action_class($tag);
3616             }
3617 0         0 $self->_init;
3618 0 0       0 $self->configure(%headerdata) if %headerdata;
3619 0         0 $self;
3620             }
3621            
3622 0     0   0 sub _init {}
3623            
3624             sub configure {
3625 0     0   0 my ($self, @param)=@_;
3626 0 0       0 @param = @{$param[0]} if ref($param[0]) eq 'ARRAY';
  0         0  
3627 0         0 my %param=@param;
3628            
3629 0 0       0 if (defined $param{Tag}) {
3630 0         0 my $tag = $param{Tag};
3631 0 0       0 if ($tag !~/^\d+$/) {
3632 0 0       0 $tag = "Action$tag" if $tag !~ /^Action/;
3633 0         0 my $tag1 = $actiontagtonum{$tag};
3634 0 0       0 Carp::croak "ACTIONRECORD '$tag1' is not defined." unless defined $tag1;
3635 0         0 $tag = $tag1;
3636             }
3637 0         0 delete $param{Tag};
3638 0         0 $self->Tag($tag);
3639 0         0 bless $self, _action_class($tag);
3640 0         0 $self->_init;
3641             }
3642 0         0 $self->SUPER::configure(%param);
3643             }
3644            
3645             sub _action_class {
3646 0     0   0 my $num = shift;
3647 0         0 my $name = $actionnumtotag{$num};
3648 0 0 0     0 if (!$name and $num >= 0x80) {
3649 0         0 $name = 'ActionUnknown';
3650             }
3651 0 0       0 if ($num >=0x80) {
3652 0         0 return "SWF::Element::ACTIONRECORD::$name";
3653             } else {
3654 0         0 return "SWF::Element::ACTIONRECORD";
3655             }
3656             }
3657            
3658             sub unpack {
3659 0     0   0 my $self = shift;
3660 0         0 my $stream = shift;
3661            
3662 0         0 $self->Tag->unpack($stream);
3663 0 0       0 if ($self->Tag >= 0x80) {
3664 0         0 bless $self, _action_class($self->Tag);
3665 0         0 $self->_init;
3666 0         0 my $len = $stream->get_UI16;
3667 0         0 my $start = $stream->tell;
3668 0         0 $self->_unpack($stream, $len);
3669             # my $read = $stream->tell - $start;
3670             # if ($read < $len) {
3671             # $stream->get_string($len-$read); # Skip the rest of tag data.
3672             # } elsif ($read > $len) {
3673             # Carp::carp ref($self)." unpacked $read bytes in excess of the described ACTIONRECORD length, $len bytes. The SWF may be collapsed or the module bug??";
3674             # } # Some SWFs have an invalid action tag length (?)
3675             }
3676             }
3677            
3678             sub pack {
3679 0     0   0 my ($self, $stream) = @_;
3680            
3681 0         0 $self->Tag->pack($stream);
3682 0 0       0 if ($self->Tag >= 0x80) {
3683 0         0 my $substream = $stream->sub_stream;
3684 0         0 $self->_pack($substream);
3685 0         0 $stream->set_UI16($substream->tell);
3686 0         0 $substream->flush_stream;
3687             }
3688             }
3689            
3690             sub _unpack {
3691 0     0   0 my $self = shift;
3692 0         0 Carp::confess "Unexpected _unpack for ".ref($self)." ".$self->Tag;
3693             }
3694            
3695             sub _pack {
3696 0     0   0 Carp::confess "Unexpected _pack";
3697             }
3698            
3699             sub tag_name {
3700 0     0   0 return $actionnumtotag{shift->Tag};
3701             }
3702            
3703             sub _create_action_tag {
3704 1     1   9 no strict 'refs';
  1         2  
  1         11045  
3705            
3706 20     20   34 my $tagname = shift;
3707 20         22 my $tagno = shift;
3708 20         24 my $tagisa = shift;
3709 20 100       46 $tagisa = defined($tagisa) ? "ACTIONRECORD::_$tagisa" : 'ACTIONRECORD';
3710 20         36 $tagname = "Action$tagname";
3711 20         79 SWF::Element::_create_class("ACTIONRECORD::$tagname", [$tagisa], Tag => 'ACTIONTagNumber', LocalLabel => "\$", @_);
3712            
3713 20         67 $actionnumtotag{$tagno} = $tagname;
3714 20         49 $actiontagtonum{$tagname} = $tagno;
3715            
3716 20         26 my $packsub = <
3717             sub \{
3718             my \$self = shift;
3719             my \$stream = shift;
3720             SUB_START
3721 20         23 my $unpacksub = $packsub;
3722            
3723 20         65 my $classname = "SWF::Element::ACTIONRECORD::$tagname";
3724 20         184 my @names = $classname->element_names;
3725 20         29 shift @names;
3726 20         23 shift @names;
3727 20         37 for my $key (@names) {
3728 31 100       158 if ($classname->element_type($key) !~ /^\$(.*)$/) {
3729 12         25 $packsub .= "\$self->$key->pack(\$stream, \@_);";
3730 12         32 $unpacksub .= "\$self->$key->unpack(\$stream, \@_);";
3731             } else {
3732 19         82 $packsub .= "\$stream->set_$1(\$self->$key);";
3733 19         65 $unpacksub .= "\$self->$key(\$stream->get_$1);";
3734             }
3735             }
3736 20         29 $unpacksub .='}';
3737 20     0   2222 *{"${classname}::_unpack"} = eval($unpacksub);
  20         110  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
3738            
3739 20 100       66 if ($tagisa eq 'ACTIONRECORD') {
3740 13         15 $packsub .='}';
3741 13     0   1277 *{"${classname}::_pack"} = eval($packsub);
  13         82  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
3742             }
3743             }
3744            
3745 0     0     sub _set_label {}
3746            
3747             @SWF::Element::ACTIONRECORD::_HasSkipCount::ISA=('SWF::Element::ACTIONRECORD');
3748             @SWF::Element::ACTIONRECORD::_HasOffset::ISA=('SWF::Element::ACTIONRECORD');
3749             @SWF::Element::ACTIONRECORD::_HasCodeSize::ISA=('SWF::Element::ACTIONRECORD::_HasOffset');
3750            
3751             _create_action_tag('Unknown', 'Unknown', undef, Data => 'BinData');
3752             _create_action_tag('GotoFrame', 0x81, undef, Frame => '$UI16');
3753             _create_action_tag('GetURL', 0x83, undef,
3754             UrlString => 'STRING',
3755             TargetString => 'STRING' );
3756             _create_action_tag('WaitForFrame', 0x8A, 'HasSkipCount',
3757             Frame => '$UI16',
3758             SkipCount => '$UI8' );
3759             _create_action_tag('SetTarget', 0x8B, undef, TargetName => 'STRING' );
3760             _create_action_tag('GotoLabel', 0x8C, undef, Label => 'STRING' );
3761             _create_action_tag('WaitForFrame2', 0x8D, 'HasSkipCount',
3762             SkipCount => '$UI8' );
3763             _create_action_tag('Push', 0x96, undef, DataList => 'Array::ACTIONDATAARRAY' );
3764             _create_action_tag('Jump', 0x99, 'HasOffset',
3765             BranchOffset=> '$SI16');
3766             _create_action_tag('GetURL2', 0x9a, undef, Method => '$UI8');
3767             _create_action_tag('If', 0x9d, 'HasOffset',
3768             BranchOffset=> '$SI16');
3769             _create_action_tag('Call', 0x9e, undef);
3770             _create_action_tag('GotoFrame2', 0x9F, undef, PlayFlag => '$UI8');
3771             _create_action_tag('ConstantPool', 0x88, undef,
3772             ConstantPool => 'Array::STRINGARRAY');
3773             _create_action_tag('DefineFunction', 0x9b, 'HasCodeSize',
3774             FunctionName => 'STRING',
3775             Params => 'Array::STRINGARRAY',
3776             CodeSize => '$UI16');
3777             _create_action_tag('StoreRegister', 0x87, undef, Register => '$UI8');
3778             _create_action_tag('With', 0x94, 'HasCodeSize',
3779             CodeSize => '$UI16');
3780            
3781             _create_action_tag('DefineFunction2', 0x8e, 'HasCodeSize',
3782             FunctionName => 'STRING',
3783             RegisterCount => '$UI8',
3784             Flags => '$UI16',
3785             Parameters => 'Array::REGISTERPARAMARRAY',
3786             CodeSize => '$UI16');
3787            
3788             _create_action_tag('Try', 0x8f, undef,
3789             TrySize => '$UI16',
3790             CatchSize => '$UI16',
3791             FinallySize => '$UI16',
3792             CatchName => 'STRING',
3793             CatchRegister => '$UI8');
3794            
3795             _create_action_tag('StrictMode', 0x89, undef, StrictMode => '$UI8');
3796            
3797             ##########
3798            
3799             package SWF::Element::ACTIONTagNumber;
3800            
3801             sub dumper {
3802 0     0     my ($self, $outputsub)=@_;
3803            
3804 0   0       $outputsub||=\&SWF::Element::_default_output;
3805 0           my $tag = $SWF::Element::ACTIONRECORD::actionnumtotag{$self->value};
3806 0 0         &$outputsub($tag ? "'$tag'" : $self->value, 0);
3807             }
3808            
3809             sub pack {
3810 0     0     my ($self, $stream) = @_;
3811            
3812 0           $stream->set_UI8($self->value);
3813             }
3814            
3815             sub unpack {
3816 0     0     my ($self, $stream) = @_;
3817            
3818 0           $self->configure($stream->get_UI8);
3819             }
3820            
3821             ##########
3822            
3823             package SWF::Element::Array::ACTIONDATAARRAY;
3824            
3825             sub unpack {
3826 0     0     my ($self, $stream, $len) = @_;
3827 0           my $start = $stream->tell;
3828            
3829 0           while ($stream->tell - $start < $len) {
3830 0           my $element = $self->new_element;
3831 0           $element->unpack($stream);
3832 0           push @$self, $element;
3833             }
3834             }
3835            
3836             ##########
3837            
3838             package SWF::Element::ACTIONDATA;
3839            
3840             sub configure {
3841 0     0     my ($self, $type, $data) = @_;
3842            
3843 0 0         if (defined $data) {
3844 0 0         if ($type eq 'Type') {
3845 0           $type = $data;
3846 0           undef $data;
3847             }
3848 0           my $class = "SWF::Element::ACTIONDATA::$type";
3849 0 0         Carp::croak "No Data type '$type' in ACTIONDATA " unless $class->can('new');
3850 0           bless $self, $class;
3851             } else {
3852 0           $data = $type;
3853             }
3854            
3855 0 0         $$self = $data if defined $data;
3856 0           $self;
3857             }
3858            
3859             sub dumper {
3860 0     0     my ($self, $outputsub, $indent)=@_;
3861            
3862 0   0       $outputsub||=\&SWF::Element::_default_output;
3863            
3864 0           my $val = $self->value;
3865            
3866 0 0         $val = "\"$val\"" if $val !~ /^-?[.\d]/;
3867            
3868 0           &$outputsub(ref($self)."->new($val)", 0);
3869             }
3870            
3871             my @actiondata_types
3872             = qw/String Property NULL UNDEF Register Boolean Double Integer Lookup Lookup/;
3873            
3874             sub pack {
3875 0     0     my ($self, $stream) = @_;
3876            
3877 0           Carp::carp "No specified type in ACTIONDATA, so pack as String. ";
3878 0           $self->configure(Type => 'String');
3879 0           $self->pack($stream);
3880             }
3881            
3882             sub unpack {
3883 0     0     my ($self, $stream) = @_;
3884 0           my $type = $stream->get_UI8;
3885            
3886 0 0         Carp::croak "Undefined type '$type' in ACTIONDATA "
3887             if $type > $#actiondata_types;
3888            
3889 0           bless $self, "SWF::Element::ACTIONDATA::$actiondata_types[$type]";
3890 0           $self->_unpack($stream, $type);
3891             }
3892            
3893 0     0     sub _unpack {};
3894            
3895             #########
3896            
3897             package SWF::Element::ACTIONDATA::String;
3898            
3899             sub pack {
3900 0     0     my ($self, $stream) = @_;
3901            
3902 0           $stream->set_UI8(0);
3903 0           $stream->set_string($self->value."\0");
3904             }
3905            
3906             sub _unpack {
3907 0     0     SWF::Element::STRING::unpack(@_);
3908             }
3909            
3910             sub dumper {
3911 0     0     my ($self, $outputsub, $indent)=@_;
3912            
3913 0   0       $outputsub||=\&SWF::Element::_default_output;
3914            
3915 0           my $val = $self->value;
3916            
3917 0           $val =~ s/([\\\$\@\"])/\\$1/gs;
3918 0           $val =~ s/([\x00-\x1F\x80-\xFF])/sprintf('\\x%.2X', ord($1))/ges;
  0            
3919 0           $val = "\"$val\"";
3920            
3921 0           &$outputsub(ref($self)."->new($val)", 0);
3922             }
3923            
3924             #########
3925             {
3926             package SWF::Element::ACTIONDATA::Property;
3927            
3928             my %prop_num =
3929             ( _x => 0,
3930             _y => 1065353216,
3931             _xscale => 1073741824,
3932             _yscale => 1077936128,
3933             _currentframe => 1082130432,
3934             _totalframes => 1084227584,
3935             _alpha => 1086324736,
3936             _visible => 1088421888,
3937             _width => 1090519040,
3938             _height => 1091567616,
3939             _rotation => 1092616192,
3940             _target => 1093664768,
3941             _framesloaded => 1094713344,
3942             _name => 1095761920,
3943             _droptarget => 1096810496,
3944             _url => 1097859072,
3945             _highquality => 1098907648,
3946             _focusrect => 1099431936,
3947             _soundbuftime => 1099956224,
3948             _quality => 1100480512,
3949             _xmouse => 1101004800,
3950             _ymouse => 1101529088,
3951             );
3952             my %num_prop = reverse %prop_num;
3953            
3954             sub pack {
3955 0     0     my ($self, $stream) = @_;
3956 0           my $data = $self->value;
3957            
3958 0           $stream->set_UI8(1);
3959 0 0         $data = (exists $prop_num{$data}) ? $prop_num{$data} : unpack('L', CORE::pack('f', $data));
3960 0           $stream->set_UI32($data);
3961            
3962             }
3963            
3964             sub _unpack {
3965 0     0     my ($self, $stream) = @_;
3966 0           my $data = $stream->get_UI32;
3967 0 0         $data = (exists $num_prop{$data}) ? $num_prop{$data} : unpack('f', CORE::pack('L', $data));
3968 0           $self->configure($data);
3969             }
3970             }
3971            
3972             #########
3973            
3974             package SWF::Element::ACTIONDATA::NULL;
3975            
3976             sub pack {
3977 0     0     $_[1]->set_UI8(2);
3978             }
3979            
3980             #########
3981            
3982             package SWF::Element::ACTIONDATA::UNDEF;
3983            
3984             sub pack {
3985 0     0     $_[1]->set_UI8(3);
3986             }
3987            
3988             #########
3989            
3990             package SWF::Element::ACTIONDATA::Register;
3991            
3992             sub pack {
3993 0     0     my ($self, $stream) = @_;
3994            
3995 0           $stream->set_UI8(4);
3996 0           $stream->set_UI8($self->value);
3997             }
3998            
3999             sub _unpack {
4000 0     0     my ($self, $stream) = @_;
4001            
4002 0           $self->configure($stream->get_UI8);
4003             }
4004            
4005             #########
4006            
4007             package SWF::Element::ACTIONDATA::Boolean;
4008            
4009             sub pack {
4010 0     0     my ($self, $stream) = @_;
4011            
4012 0           $stream->set_UI8(5);
4013 0           $stream->set_UI8($self->value);
4014             }
4015            
4016             sub _unpack {
4017 0     0     my ($self, $stream) = @_;
4018            
4019 0           $self->configure($stream->get_UI8);
4020             }
4021            
4022             #########
4023            
4024             package SWF::Element::ACTIONDATA::Lookup;
4025            
4026             sub pack {
4027 0     0     my ($self, $stream) = @_;
4028            
4029 0 0         if ((my $v = $self->value) >= 256) {
4030 0           $stream->set_UI8(9);
4031 0           $stream->set_UI16($v);
4032             } else {
4033 0           $stream->set_UI8(8);
4034 0           $stream->set_UI8($v);
4035             }
4036             }
4037            
4038             sub _unpack {
4039 0     0     my ($self, $stream, $type) = @_;
4040            
4041 0 0         $self->configure($type == 8 ? $stream->get_UI8 : $stream->get_UI16);
4042             }
4043            
4044             #########
4045            
4046             package SWF::Element::ACTIONDATA::Integer;
4047            
4048             sub pack {
4049 0     0     my ($self, $stream) = @_;
4050            
4051 0           $stream->set_UI8(7);
4052 0           $stream->set_SI32($self->value); # really signed?
4053             }
4054            
4055             sub _unpack {
4056 0     0     my ($self, $stream) = @_;
4057            
4058 0           $self->configure($stream->get_SI32); # really signed?
4059             }
4060            
4061             #########
4062             {
4063             package SWF::Element::ACTIONDATA::Double; # IEEE754 double support needed.
4064            
4065             my $BE = (CORE::pack('s',1) eq CORE::pack('n',1));
4066             my $INF = "\x00\x00\x00\x00\x00\x00\xf0\x7f";
4067             my $NINF = "\x00\x00\x00\x00\x00\x00\xf0\xff";
4068             my $MANTISSA = ~$NINF;
4069            
4070             sub pack {
4071 0     0     my ($self, $stream) = @_;
4072            
4073 0           $stream->set_UI8(6);
4074 0           my $value = $self->value;
4075 0           my $data;
4076 0 0         if ($value eq 'NaN') {
    0          
    0          
4077 0           $data = "\x00\x00\x00\x00\x00\x00\xf8\x7f";
4078             } elsif ($value eq 'Infinity') {
4079 0           $data = $INF;
4080             } elsif ($value eq '-Infinity') {
4081 0           $data = $NINF;
4082             } else {
4083 0           $data = CORE::pack('d', $value);
4084 0 0         $data = reverse $data if $BE;
4085             }
4086 0           $stream->set_string(substr($data, -4));
4087 0           $stream->set_string(substr($data,0,4));
4088             }
4089            
4090             sub _unpack {
4091 0     0     my ($self, $stream) = @_;
4092 0           my $data = $stream->get_string(4);
4093 0           $data = $stream->get_string(4). $data;
4094            
4095 0           my $value;
4096            
4097 0 0 0       if (($data & $INF) eq $INF and ($data & $MANTISSA) ne "\x00" x 8) {
    0          
    0          
4098 0           $value = 'NaN';
4099             } elsif ($data eq $INF) {
4100 0           $value = 'Infinity';
4101             } elsif ($data eq $NINF) {
4102 0           $value = '-Infinity';
4103             } else {
4104 0 0         $data = reverse $data if $BE;
4105 0           $value = unpack('d',$data);
4106             }
4107 0           $self->configure($value);
4108             }
4109            
4110             }
4111            
4112             ##########
4113            
4114             package SWF::Element::CLIPACTIONRECORD;
4115            
4116             sub unpack {
4117 0     0     my ($self, $stream) = @_;
4118            
4119 0           my $flag = 0;
4120 0           $stream->_lock_version;
4121 0 0         if ($stream->Version >= 6) {
4122 0           $flag = $self->EventFlags ($stream->get_UI32);
4123             } else {
4124 0           $flag = $self->EventFlags ($stream->get_UI16);
4125             }
4126 0 0         return if $flag == 0;
4127 0           my $size = $stream->get_UI32;
4128 0           my $start = $stream->tell;
4129 0 0         $self->KeyCode($stream->get_UI8)if $self->ClipEventKeyPress;
4130 0           $self->Actions->unpack($stream);
4131 0           my $remain = $stream->tell - $start - $size;
4132 0 0         $stream->get_string($remain) if $remain > 0;
4133             }
4134            
4135             sub pack {
4136 0     0     my ($self, $stream) = @_;
4137            
4138 0           $stream->_lock_version;
4139 0 0         if ($stream->Version >= 6) {
4140 0           $stream->set_UI32($self->EventFlags);
4141             } else {
4142 0           $stream->set_UI16($self->EventFlags & 0xffff);
4143             }
4144            
4145 0           my $tempstream = $stream->sub_stream;
4146 0 0         $tempstream->set_UI8($self->KeyCode) if $self->ClipEventKeyPress;
4147 0           $self->Actions->pack($tempstream);
4148 0           $stream->set_UI32($tempstream->tell);
4149 0           $tempstream->flush_stream;
4150             }
4151            
4152             {
4153             my $bit = 0;
4154             for my $f
4155             ( qw/ Load EnterFrame Unload MouseMove
4156             MouseDown MouseUp KeyDown KeyUp
4157             Data Initialize Press Release
4158             ReleaseOutside RollOver RollOut DragOver
4159             DragOut KeyPress Construct
4160             / ) {
4161             SWF::Element::_create_flag_accessor("ClipEvent$f", 'EventFlags', $bit++);
4162             }
4163             }
4164            
4165             ##########
4166            
4167             package SWF::Element::Array::ACTIONRECORDARRAY;
4168            
4169             sub pack {
4170 0     0     my $self = shift;
4171 0           my $stream = $_[0];
4172            
4173             # Add ActionEnd if there is not.
4174            
4175 0 0         push @$self, SWF::Element::ACTIONRECORD->new(Tag=>'ActionEnd') if $self->[-1]->Tag != 0;
4176            
4177 0           my $actionstream = SWF::BinStream::Write->new($stream->Version);
4178 0           my %labels;
4179 0           my $count = 0;
4180            
4181             # Keep label positions.
4182            
4183 0           for my $element (@$self) {
4184 0 0         $labels{$element->LocalLabel} = [$count, $actionstream->tell] if ($element->LocalLabel);
4185 0           $count++;
4186 0           $element->pack($actionstream, @_);
4187             }
4188            
4189 0           my %marks = $actionstream->mark;
4190 0           my @replace;
4191            
4192 0           for my $label (keys %marks) {
4193 0           (my $label1 = $label)=~s/\#.*$//; # inner local label
4194 0 0         Carp::croak "Can't find LocalLabel '$label1' " unless defined $labels{$label1};
4195            
4196 0           while(my ($tell, $obj) = splice(@{$marks{$label}}, 0, 2)) {
  0            
4197 0           my ($data, $length) = $obj->_resolve_label($tell, $labels{$label1}, $self);
4198            
4199 0 0 0       if ($length >= 2 and $tell % 1024 == 1023) {
4200 0           my @data = split //, $data;
4201 0           push @{$replace[$tell>>10]}, [1023, 1, $data[0]];
  0            
4202 0           push @{$replace[($tell>>10)+1]}, [0, 1, $data[1]];
  0            
4203             } else {
4204 0           push @{$replace[$tell>>10]}, [$tell % 1024, $length, $data];
  0            
4205             }
4206             }
4207             }
4208            
4209 0           while($actionstream->Length > 0) {
4210 0           my $buf = $actionstream->flush_stream(1024);
4211 0           my $replace1 = shift @replace;
4212 0           while (my $replace2 = shift @$replace1) {
4213 0           my ($pos, $len, $r) = @$replace2;
4214 0           substr($buf, $pos, $len) = $r;
4215             }
4216 0           $stream->set_string($buf);
4217             }
4218             }
4219            
4220             {
4221             my $label;
4222            
4223             sub unpack {
4224 0     0     my ($self, $stream, $len) = @_;
4225 0           my @byteoffset;
4226 0           my $start = $stream->tell;
4227            
4228 0   0       while(!defined $len or $stream->tell - $start < $len) {
4229 0           push @byteoffset, $stream->tell-$start;
4230 0           my $element = $self->new_element;
4231 0           $element->unpack($stream);
4232 0           push @$self, $element;
4233 0 0 0       last if !defined $len and $element->Tag == 0;
4234             }
4235 0           $label = 'A';
4236 0           for (my $i = 0; $i < @byteoffset; $i++) {
4237 0           $self->[$i]->_set_label($i, $self, \@byteoffset);
4238             }
4239             }
4240            
4241             sub _get_label {
4242 0     0     $label++;
4243             }
4244             }
4245            
4246             ##########
4247            
4248             package SWF::Element::ACTIONRECORD::_HasSkipCount;
4249            
4250             sub _set_label {
4251 0     0     my ($self, $pos, $actionstream) = @_;
4252 0           my $skip = $self->SkipCount;
4253 0           my $dst = $actionstream->[$pos + $skip+1];
4254            
4255 0           my $l = $dst->LocalLabel;
4256 0 0         unless ($l) {
4257 0           $l = $actionstream->_get_label;
4258 0           $dst->LocalLabel($l);
4259             }
4260 0           $self->SkipCount("$l#$skip");
4261             }
4262            
4263             ##########
4264            
4265             package SWF::Element::ACTIONRECORD::ActionWaitForFrame;
4266            
4267             sub _pack {
4268 0     0     my ($self, $stream) = @_;
4269            
4270 0           $stream->set_UI16($self->Frame);
4271 0           my $skip = $self->SkipCount;
4272            
4273 0 0         if ($skip =~ /^[^\d]/) {
4274 0           $stream->mark($skip, bless [$self], 'SWF::Element::_Label::SkipCount');
4275 0           $stream->set_UI8(0);
4276             } else {
4277 0           $stream->set_UI8($skip);
4278             }
4279             }
4280            
4281             ##########
4282            
4283             package SWF::Element::ACTIONRECORD::ActionWaitForFrame2;
4284            
4285             sub _pack {
4286 0     0     my ($self, $stream) = @_;
4287 0           my $skip = $self->SkipCount;
4288            
4289 0 0         if ($skip =~ /^[^\d]/) {
4290 0           $stream->mark($skip, bless [$self], 'SWF::Element::_Label::SkipCount');
4291 0           $stream->set_UI8(0);
4292             } else {
4293 0           $stream->set_UI8($skip);
4294             }
4295             }
4296            
4297             ##########
4298            
4299             package SWF::Element::ACTIONRECORD::_HasOffset;
4300            
4301             sub _set_label {
4302 0     0     my ($self, $pos, $actionstream, $byteoffset) = @_;
4303 0           my $offset = $self->_Offset;
4304 0           my $j = $pos+1;
4305 0           my $set = $byteoffset->[$j];
4306 0           my $dst = $set;
4307 0 0         if ($offset < 0) {
4308 0   0       while ($j>=0 and ($dst-$set) > $offset) {
4309 0           $j--;
4310 0           $dst = $byteoffset->[$j];
4311             }
4312             } else {
4313 0   0       while ($j<@$byteoffset and ($dst-$set) < $offset) {
4314 0           $j++;
4315 0           $dst = $byteoffset->[$j];
4316             }
4317             }
4318 0 0         if ($dst-$set == $offset) {
4319 0           my $l = $actionstream->[$j]->LocalLabel;
4320 0 0         unless ($l) {
4321 0           $l = $actionstream->_get_label;
4322 0           $actionstream->[$j]->LocalLabel($l);
4323             }
4324 0           $self->_Offset("$l#$offset");
4325             }
4326             }
4327            
4328             ##########
4329            
4330             package SWF::Element::ACTIONRECORD::ActionJump;
4331            
4332             sub _pack {
4333 0     0     my ($self, $stream) = @_;
4334 0           my $offset = $self->BranchOffset;
4335            
4336 0 0         if ($offset =~ /^[^\d\-]/) {
4337 0           $stream->mark($offset, bless [$self], 'SWF::Element::_Label::Offset');
4338 0           $stream->set_SI16(0);
4339             } else {
4340 0           $stream->set_SI16($offset);
4341             }
4342             }
4343            
4344             *SWF::Element::ACTIONRECORD::ActionJump::_Offset = \&BranchOffset;
4345             *SWF::Element::ACTIONRECORD::ActionIf::_Offset = \&BranchOffset;
4346             *SWF::Element::ACTIONRECORD::ActionIf::_pack = \&_pack;
4347            
4348             ##########
4349            
4350             package SWF::Element::ACTIONRECORD::ActionGetURL2;
4351            
4352             SWF::Element::_create_flag_accessor('SendVarsMethod', 'Method', 0, 2);
4353             SWF::Element::_create_flag_accessor('LoadTargetFlag', 'Method', 6);
4354             SWF::Element::_create_flag_accessor('LoadVariablesFlag', 'Method', 7);
4355            
4356             ##########
4357            
4358             package SWF::Element::ACTIONRECORD::ActionDefineFunction;
4359            
4360             sub _pack {
4361 0     0     my ($self, $stream) = @_;
4362            
4363 0           $self->FunctionName->pack($stream);
4364 0           $self->Params->pack($stream);
4365            
4366 0           my $offset = $self->CodeSize;
4367            
4368 0 0         if ($offset =~ /^\D/) {
4369 0           $stream->mark($offset, bless [$self], 'SWF::Element::_Label::CodeSize');
4370 0           $stream->set_UI16(0);
4371             } else {
4372 0           $stream->set_UI16($offset);
4373             }
4374             }
4375            
4376             *SWF::Element::ACTIONRECORD::ActionDefineFunction::_Offset = \&CodeSize;
4377            
4378             ##########
4379            
4380             package SWF::Element::ACTIONRECORD::ActionWith;
4381            
4382             sub _pack {
4383 0     0     my ($self, $stream) = @_;
4384            
4385 0           my $offset = $self->CodeSize;
4386            
4387 0 0         if ($offset =~ /^\D/) {
4388 0           $stream->mark($offset, bless [$self], 'SWF::Element::_Label::CodeSize');
4389 0           $stream->set_UI16(0);
4390             } else {
4391 0           $stream->set_UI16($offset);
4392             }
4393             }
4394            
4395             *SWF::Element::ACTIONRECORD::ActionWith::_Offset = \&CodeSize;
4396            
4397             ##########
4398            
4399             package SWF::Element::ACTIONRECORD::ActionDefineFunction2;
4400            
4401             sub _pack {
4402 0     0     my ($self, $stream) = @_;
4403            
4404 0           $self->FunctionName->pack($stream);
4405 0           $stream->set_UI16(scalar @{$self->Parameters});
  0            
4406 0           $stream->set_UI8($self->RegisterCount);
4407 0           $stream->set_UI16($self->Flags);
4408 0           $self->Parameters->pack($stream);
4409            
4410 0           my $offset = $self->CodeSize;
4411            
4412 0 0         if ($offset =~ /^\D/) {
4413 0           $stream->mark($offset, bless [$self], 'SWF::Element::_Label::CodeSize');
4414 0           $stream->set_UI16(0);
4415             } else {
4416 0           $stream->set_UI16($offset);
4417             }
4418             }
4419            
4420             {
4421 1     1   19 no warnings 'redefine';
  1         2  
  1         303  
4422            
4423             *SWF::Element::ACTIONRECORD::ActionDefineFunction2::_unpack = sub {
4424 0     0     my ($self, $stream) = @_;
4425            
4426 0           $self->FunctionName->unpack($stream);
4427 0           my $numparams = $stream->get_UI16;
4428 0           $self->RegisterCount($stream->get_UI8);
4429 0           $self->Flags($stream->get_UI16);
4430 0           my $params = $self->Parameters;
4431 0           for (my $c = 0 ; $c < $numparams; $c++) {
4432 0           my $p = $params->new_element;
4433 0           $p->unpack($stream);
4434 0           push @$params, $p;
4435             }
4436 0           $self->CodeSize($stream->get_UI16);
4437             }
4438             }
4439            
4440             *SWF::Element::ACTIONRECORD::ActionDefineFunction2::_Offset = \&CodeSize;
4441            
4442             {
4443             my $bit = 0;
4444             for my $f (qw/ This Arguments Super /) {
4445             SWF::Element::_create_flag_accessor("Preload${f}Flag", 'Flags', $bit++);
4446             SWF::Element::_create_flag_accessor("Suppress${f}Flag", 'Flags', $bit++);
4447             }
4448             for my $f (qw/ Root Parent Global /) {
4449             SWF::Element::_create_flag_accessor("Preload${f}Flag", 'Flags', $bit++);
4450             }
4451             }
4452            
4453             ##########
4454            
4455             package SWF::Element::ACTIONRECORD::ActionTry;
4456            
4457             {
4458 1     1   5 no warnings 'redefine';
  1         2  
  1         2130  
4459            
4460             *SWF::Element::ACTIONRECORD::ActionTry::_pack = sub {
4461 0     0     my ($self, $stream) = @_;
4462            
4463 0           my $flags = 0;
4464 0           my ($trylabel) = ($self->TrySize =~ /^(.*#)/);
4465 0           my ($catchlabel) = ($self->CatchSize =~ /^(.*#)/);
4466 0           my ($finallylabel) = ($self->FinallySize =~ /^(.*#)/);
4467            
4468 0 0         $flags |= 4 if defined $self->CatchRegister;
4469 0 0 0       $flags |= 2 if ($finallylabel and $finallylabel ne $catchlabel or !$finallylabel and $self->FinallySize != 0);
      0        
      0        
4470 0 0 0       $flags |= 1 if ($catchlabel and $catchlabel ne $trylabel or !$catchlabel and $self->CatchSize != 0);
      0        
      0        
4471            
4472 0           $stream->set_UI8($flags);
4473            
4474 0           my $byteoffset;
4475 0           my $current_byteoffset = $stream->tell;
4476 0           for my $n (qw/TrySize CatchSize FinallySize/) {
4477 0           my $offset = $self->$n;
4478 0 0         if ($offset =~ /^\D/) {
4479 0           my $label = bless [$self, \$byteoffset], "SWF::Element::_Label::$n";
4480 0           $stream->mark($offset, $label);
4481 0           $stream->set_UI16(0);
4482             } else {
4483 0           $stream->set_UI16($offset);
4484             }
4485             }
4486            
4487 0 0         if ($flags & 4) {
4488 0           $stream->set_UI8($self->CatchRegister);
4489             } else {
4490 0           $self->CatchName->pack($stream);
4491             }
4492 0           $byteoffset = $stream->tell - $current_byteoffset;
4493             };
4494            
4495             *SWF::Element::ACTIONRECORD::ActionTry::_unpack = sub {
4496 0     0     my ($self, $stream,$len) = @_;
4497            
4498 0           my $flags = $stream->get_UI8;
4499 0           $self->TrySize($stream->get_UI16);
4500 0           my $catchsize = $stream->get_UI16;
4501 0 0         $self->CatchSize($catchsize) if $flags & 1;
4502 0           my $finallysize = $stream->get_UI16;
4503 0 0         $self->FinallySize($finallysize) if $flags & 2;
4504 0 0         if ($flags & 4) {
4505 0           $self->CatchRegister($stream->get_UI8);
4506             } else {
4507 0           $self->CatchName->unpack($stream);
4508             }
4509             };
4510             }
4511            
4512             sub _set_label {
4513 0     0     my ($self, $pos, $actionstream, $byteoffset) = @_;
4514 0           my $j = $pos+1;
4515            
4516 0           for my $x_size (qw/ TrySize CatchSize FinallySize /) {
4517 0           my $offset = $self->$x_size;
4518            
4519 0 0 0       next if !defined $offset or $offset <= 0;
4520            
4521 0           my $set = $byteoffset->[$j];
4522 0           my $dst = $set;
4523            
4524 0   0       while ($j<@$byteoffset and ($dst-$set) < $offset) {
4525 0           $j++;
4526 0           $dst = $byteoffset->[$j];
4527             }
4528            
4529 0 0         if ($dst-$set == $offset) {
4530 0           my $l = $actionstream->[$j]->LocalLabel;
4531 0 0         unless ($l) {
4532 0           $l = $actionstream->_get_label;
4533 0           $actionstream->[$j]->LocalLabel($l);
4534             }
4535 0           $self->$x_size("$l#$offset");
4536             }
4537             }
4538            
4539             }
4540            
4541             ##########
4542            
4543             package SWF::Element::_Label::SkipCount;
4544            
4545             sub _resolve_label {
4546 0     0     my ($self, $pos, $dst, $actions) = @_;
4547 0           my $count = 1;
4548            
4549 0           for my $element (@$actions) {
4550 0 0         last if $element eq $self->[0];
4551 0           $count++;
4552             }
4553 0 0         Carp::croak "SkipCount of ".ref($self->[0])." cannot refer backward " if $dst->[0] < $count;
4554 0           return (CORE::pack('C', $dst->[0] - $count), 1);
4555             }
4556            
4557             ##########
4558            
4559             package SWF::Element::_Label::Offset;
4560            
4561             sub _resolve_label {
4562 0     0     my ($self, $pos, $dst) = @_;
4563 0           return (CORE::pack('v', $dst->[1] - $pos - 2), 2);
4564             }
4565            
4566             ##########
4567            
4568             package SWF::Element::_Label::CodeSize;
4569            
4570             sub _resolve_label {
4571 0     0     my ($self, $pos, $dst) = @_;
4572 0           my $offset = $dst->[1] - $pos - 2;
4573 0 0         Carp::croak "Can't set negative code size for ".ref($self->[0]) if $offset < 0;
4574 0           return (CORE::pack('v', $offset), 2);
4575             }
4576            
4577             ##########
4578            
4579             package SWF::Element::_Label::TrySize;
4580            
4581             sub _resolve_label {
4582 0     0     my ($self, $pos, $dst) = @_;
4583 0           my $offset = $dst->[1] - $pos - ${$self->[1]};
  0            
4584 0           (my $trylabel = $self->[0]->TrySize) =~ s/#.*$//;
4585            
4586 0 0         Carp::croak "Can't set negative code size for TrySize" if $offset < 0;
4587 0           $self->[0]->TrySize("$trylabel#$offset");
4588 0           return (CORE::pack('v', $offset), 2);
4589             }
4590            
4591             ##########
4592            
4593             package SWF::Element::_Label::CatchSize;
4594            
4595             sub _resolve_label {
4596 0     0     my ($self, $pos, $dst) = @_;
4597 0           (my $trysize = $self->[0]->TrySize) =~ s/^.*#//;
4598 0           (my $catchlabel = $self->[0]->CatchSize) =~ s/#.*$//;
4599 0           my $offset = $dst->[1] - $pos - ${$self->[1]} - $trysize + 2;
  0            
4600 0 0         Carp::croak "Can't set negative code size for CatchSize" if $offset < 0;
4601 0           $self->[0]->CatchSize("$catchlabel#$offset");
4602 0           return (CORE::pack('v', $offset), 2);
4603             }
4604            
4605             ##########
4606            
4607             package SWF::Element::_Label::FinallySize;
4608            
4609             sub _resolve_label {
4610 0     0     my ($self, $pos, $dst) = @_;
4611 0           (my $trysize = $self->[0]->TrySize) =~ s/^.*#//;
4612 0           (my $catchsize = $self->[0]->CatchSize) =~ s/^.*#//;
4613 0           (my $finallylabel = $self->[0]->FinallySize) =~ s/#.*$//;
4614 0           my $offset = $dst->[1] - $pos - ${$self->[1]} - $trysize - $catchsize + 4;
  0            
4615 0 0         Carp::croak "Can't set negative code size for FinallySize" if $offset < 0;
4616 0           $self->[0]->FinallySize("$finallylabel#$offset");
4617 0           return (CORE::pack('v', $offset), 2);
4618             }
4619            
4620            
4621            
4622             #### Video ####
4623             ##########
4624            
4625             package SWF::Element::Tag::DefineVideoStream;
4626            
4627             SWF::Element::_create_flag_accessor('VideoFlagsSmoothing', 'VideoFlags', 0);
4628             SWF::Element::_create_flag_accessor('VideoFlagsDeblocking', 'VideoFlags', 1, 2);
4629            
4630             ##########
4631            
4632             package SWF::Element::Tag::VideoFrame;
4633            
4634             sub _unpack {
4635 0     0     my ($self, $stream) = @_;
4636            
4637 0           $self->StreamID->unpack($stream);
4638 0           $self->FrameNum($stream->get_UI16);
4639 0           $self->VideoData->unpack($stream, $self->Length - 4);
4640             }
4641            
4642             ##########
4643            
4644             1;
4645             __END__