line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SWF::Parser;
|
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
11
|
use strict;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
57
|
|
4
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION);
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
135
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
$VERSION = '0.11';
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
6
|
use SWF::BinStream;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
23
|
|
9
|
1
|
|
|
1
|
|
15
|
use Carp;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
606
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub new {
|
12
|
1
|
|
|
1
|
1
|
143
|
my $class = shift;
|
13
|
1
|
|
|
|
|
6
|
my %param = @_;
|
14
|
1
|
|
|
|
|
7
|
my $self = { _tag => {},
|
15
|
|
|
|
|
|
|
_version => 5,
|
16
|
|
|
|
|
|
|
_aborted => 0,
|
17
|
|
|
|
|
|
|
};
|
18
|
0
|
|
|
0
|
|
0
|
$self->{_header_callback} =
|
19
|
|
|
|
|
|
|
$param{'header-callback'}
|
20
|
|
|
|
|
|
|
|| $param{'header_callback'}
|
21
|
1
|
|
50
|
|
|
8
|
|| (sub {0});
|
22
|
0
|
|
|
0
|
|
0
|
$self->{_tag_callback} =
|
23
|
|
|
|
|
|
|
$param{'tag-callback'}
|
24
|
|
|
|
|
|
|
|| $param{'tag_callback'}
|
25
|
1
|
|
50
|
|
|
9
|
|| (sub {0});
|
26
|
1
|
50
|
33
|
|
|
7
|
$self->{_header} = {} unless $param{header} and $param{header} =~ /^no(?:ne)?$/;
|
27
|
1
|
|
33
|
0
|
|
19
|
$self->{_stream}=$param{'stream'}||(SWF::BinStream::Read->new('', sub{ die "The stream ran short by $_[0] bytes."}));
|
|
0
|
|
|
|
|
0
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
1
|
|
|
|
|
7
|
bless $self, $class;
|
31
|
|
|
|
|
|
|
}
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub parse {
|
34
|
2
|
|
|
2
|
1
|
6
|
my ($self, $data) = @_;
|
35
|
2
|
|
|
|
|
5
|
my $stream = $self->{_stream};
|
36
|
|
|
|
|
|
|
|
37
|
2
|
50
|
|
|
|
8
|
if ($self->{_aborted}) {
|
38
|
0
|
|
|
|
|
0
|
carp 'The SWF parser has been aborted';
|
39
|
0
|
|
|
|
|
0
|
return $self;
|
40
|
|
|
|
|
|
|
}
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# unless (defined $data) {
|
43
|
|
|
|
|
|
|
# if (my $bytes=$stream->Length) {
|
44
|
|
|
|
|
|
|
# carp "Data remains $bytes bytes in the stream.";
|
45
|
|
|
|
|
|
|
# }
|
46
|
|
|
|
|
|
|
# return $self;
|
47
|
|
|
|
|
|
|
# }
|
48
|
2
|
|
|
|
|
16
|
$stream->add_stream($data);
|
49
|
2
|
|
|
|
|
31
|
eval {{
|
50
|
2
|
100
|
|
|
|
4
|
unless (exists $self->{_header}) {
|
|
3
|
|
|
|
|
1147
|
|
51
|
2
|
|
66
|
|
|
15
|
$self->parsetag while !$self->{_aborted} and $stream->Length;
|
52
|
|
|
|
|
|
|
} else {
|
53
|
1
|
|
|
|
|
5
|
$self->parseheader;
|
54
|
1
|
50
|
33
|
|
|
10
|
redo if !$self->{_aborted} and $stream->Length;
|
55
|
|
|
|
|
|
|
}
|
56
|
|
|
|
|
|
|
}};
|
57
|
2
|
50
|
|
|
|
15
|
if ($@) {
|
58
|
0
|
0
|
|
|
|
0
|
return $self if ($@=~/^The stream ran short by/);
|
59
|
0
|
|
|
|
|
0
|
die $@;
|
60
|
|
|
|
|
|
|
}
|
61
|
2
|
|
|
|
|
20
|
$self;
|
62
|
|
|
|
|
|
|
}
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub parse_file {
|
65
|
1
|
|
|
1
|
1
|
19
|
my($self, $file) = @_;
|
66
|
1
|
|
|
1
|
|
7
|
no strict 'refs'; # so that a symbol ref as $file works
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
901
|
|
67
|
1
|
|
|
|
|
5
|
local(*F);
|
68
|
1
|
50
|
33
|
|
|
10
|
unless (ref($file) || $file =~ /^\*[\w:]+$/) {
|
69
|
|
|
|
|
|
|
# Assume $file is a filename
|
70
|
1
|
50
|
|
|
|
54
|
open(F, $file) || die "Can't open $file: $!";
|
71
|
1
|
|
|
|
|
5
|
$file = *F;
|
72
|
|
|
|
|
|
|
}
|
73
|
1
|
|
|
|
|
4
|
binmode($file);
|
74
|
1
|
|
|
|
|
5
|
my $chunk = '';
|
75
|
1
|
|
66
|
|
|
73
|
while(!$self->{_aborted} and read($file, $chunk, 4096)) {
|
76
|
1
|
|
|
|
|
7
|
$self->parse($chunk);
|
77
|
|
|
|
|
|
|
}
|
78
|
1
|
|
|
|
|
18
|
close($file);
|
79
|
1
|
50
|
|
|
|
9
|
$self->eof unless $self->{_aborted};
|
80
|
|
|
|
|
|
|
}
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub eof
|
83
|
|
|
|
|
|
|
{
|
84
|
1
|
|
|
1
|
0
|
5
|
shift->parse(undef);
|
85
|
|
|
|
|
|
|
}
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub parseheader {
|
88
|
1
|
|
|
1
|
1
|
2
|
my $self = shift;
|
89
|
1
|
|
|
|
|
3
|
my $stream = $self->{_stream};
|
90
|
1
|
|
|
|
|
3
|
my $header = $self->{_header};
|
91
|
|
|
|
|
|
|
|
92
|
1
|
50
|
|
|
|
10
|
unless (exists $header->{signature}) {
|
93
|
1
|
|
|
|
|
7
|
my $h = $header->{signature} = $stream->get_string(3);
|
94
|
1
|
50
|
33
|
|
|
25
|
Carp::confess "This is not SWF stream " if ($h ne 'CWS' and $h ne 'FWS');
|
95
|
|
|
|
|
|
|
}
|
96
|
1
|
50
|
|
|
|
9
|
$stream->Version($header->{version} = $self->{_version} = $stream->get_UI8) unless exists $header->{version};
|
97
|
1
|
50
|
|
|
|
16
|
$header->{filelen} = $stream->get_UI32 unless exists $header->{filelen};
|
98
|
1
|
50
|
|
|
|
25
|
$stream->add_codec('Zlib') if ($header->{signature} eq 'CWS');
|
99
|
1
|
50
|
|
|
|
13
|
$header->{nbits} = $stream->get_bits(5) unless exists $header->{nbits};
|
100
|
1
|
|
|
|
|
3
|
my $nbits = $header->{nbits};
|
101
|
1
|
50
|
|
|
|
17
|
$header->{xmin} = $stream->get_sbits($nbits) unless exists $header->{xmin};
|
102
|
1
|
50
|
|
|
|
13
|
$header->{xmax} = $stream->get_sbits($nbits) unless exists $header->{xmax};
|
103
|
1
|
50
|
|
|
|
7
|
$header->{ymin} = $stream->get_sbits($nbits) unless exists $header->{ymin};
|
104
|
1
|
50
|
|
|
|
12
|
$header->{ymax} = $stream->get_sbits($nbits) unless exists $header->{ymax};
|
105
|
1
|
50
|
|
|
|
9
|
$header->{rate} = $stream->get_UI16 / 256 unless exists $header->{rate};
|
106
|
1
|
50
|
|
|
|
23
|
$header->{count} = $stream->get_UI16 unless exists $header->{count};
|
107
|
|
|
|
|
|
|
|
108
|
1
|
|
|
|
|
16
|
$self->{_header_callback}->($self, @{$header}{qw(signature version filelen xmin ymin xmax ymax rate count)});
|
|
1
|
|
|
|
|
7
|
|
109
|
1
|
|
|
|
|
42
|
delete $self->{_header};
|
110
|
|
|
|
|
|
|
}
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub parsetag {
|
113
|
6
|
|
|
6
|
1
|
46
|
my $self = shift;
|
114
|
6
|
|
|
|
|
15
|
my $tag = $self->{_tag};
|
115
|
6
|
|
|
|
|
10
|
my $stream = $self->{_stream};
|
116
|
6
|
50
|
|
|
|
35
|
$tag->{header}=$stream->get_UI16 unless exists $tag->{header};
|
117
|
6
|
50
|
|
|
|
119
|
unless (exists $tag->{length}) {
|
118
|
6
|
|
|
|
|
13
|
my $length = ($tag->{header} & 0x3f);
|
119
|
6
|
100
|
|
|
|
19
|
$length=$stream->get_UI32 if ($length == 0x3f);
|
120
|
6
|
|
|
|
|
24
|
$tag->{length}=$length;
|
121
|
|
|
|
|
|
|
}
|
122
|
6
|
50
|
|
|
|
25
|
unless (exists $tag->{data}) {
|
123
|
6
|
|
|
|
|
20
|
$stream->_require($tag->{length});
|
124
|
6
|
|
|
|
|
11
|
$tag->{data} = $stream;
|
125
|
6
|
|
|
|
|
21
|
$tag->{_next_pos} = $stream->tell + $tag->{length};
|
126
|
|
|
|
|
|
|
}
|
127
|
6
|
|
|
|
|
11
|
eval {
|
128
|
6
|
|
|
|
|
30
|
$self->{_tag_callback}->($self, $tag->{header} >> 6, $tag->{length}, $tag->{data});
|
129
|
|
|
|
|
|
|
};
|
130
|
6
|
50
|
|
|
|
231
|
if ($@) {
|
131
|
0
|
0
|
|
|
|
0
|
Carp::confess 'Short!' if ($@=~/^The stream ran short by/);
|
132
|
0
|
|
|
|
|
0
|
die $@;
|
133
|
|
|
|
|
|
|
}
|
134
|
6
|
|
|
|
|
23
|
my $offset = $tag->{_next_pos} - $stream->tell;
|
135
|
6
|
50
|
|
|
|
17
|
Carp::confess 'Short!' if $offset < 0;
|
136
|
6
|
50
|
|
|
|
32
|
$stream->get_string($offset) if $offset > 0;
|
137
|
6
|
|
|
|
|
48
|
$self->{_tag}={};
|
138
|
|
|
|
|
|
|
}
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub abort {
|
141
|
0
|
|
|
0
|
1
|
|
shift->{_aborted} = 1;
|
142
|
|
|
|
|
|
|
}
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
1;
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
__END__
|