File Coverage

blib/lib/SWF/Header.pm
Criterion Covered Total %
statement 54 64 84.3
branch 9 22 40.9
condition 1 3 33.3
subroutine 9 11 81.8
pod 6 6 100.0
total 79 106 74.5


line stmt bran cond sub pod time code
1             package SWF::Header;
2            
3 1     1   21421 use strict;
  1         2  
  1         36  
4 1     1   4 use vars qw($VERSION);
  1         2  
  1         51  
5             $VERSION = '0.04';
6            
7 1     1   897 use SWF::BinStream;
  1         31793  
  1         24  
8 1     1   9 use Carp;
  1         1  
  1         705  
9            
10             =head1 NAME
11            
12             SWF::Header - extract header information from SWF files.
13            
14             =head1 SYNOPSIS
15            
16             use SWF::Header;
17             my $header_data = SWF::Header->read_file('/path/to/file.swf');
18            
19             or
20            
21             my $header_data = SWF::Header->read_data($binary_data);
22            
23             or
24            
25             my $h = SWF::Header->new();
26             my %headers = map { $_ => $h->read_file($_) } @files;
27            
28            
29             =head1 DESCRIPTION
30            
31             I pulls the descriptive information out of the header of a shockwave (.swf) file. It returns a hashref of height, width, duration, framerate, shockwave version and file size.
32            
33             =head2 METHODS
34            
35             =over 4
36            
37             =item new()
38            
39             Creates a reader object. You don't normally need to call the constructor directly unless you want to read several files. Either read_file or read_data will construct an object to do the work if called as a class method.
40            
41             =cut
42            
43             sub new {
44 2     2 1 15 my $class = shift;
45 2         8 my $self = {
46             _version => 5,
47             _stream => undef,
48             };
49 2         7 return bless $self, $class;
50             }
51            
52             =item stream( $stream )
53            
54             A set or get method that can be used to provide an SWF::BinStream::Read object you want to work with. If none is supplied or exists already, calls new_stream to create a new one.
55            
56             =cut
57            
58             sub stream {
59 15     15 1 23 my ($self, $s) = @_;
60 15 50       29 return $self->{_stream} = $s if $s;
61 15 50       92 return $self->{_stream} if $self->{_stream};
62 0         0 return $self->new_stream;
63             }
64            
65             =item new_stream()
66            
67             Resets the reader's stream to a new SWF::BinStream::Read object, ready to start from scratch. Both read_file and read_data call this method before handing over to parse_header.
68            
69             =cut
70            
71             sub new_stream {
72 1     1 1 2 my ($self, $data) = @_;
73 1     0   14 return $self->{_stream} = SWF::BinStream::Read->new($data, sub{ Carp::croak("The stream ran short by $_[0] bytes.") });
  0         0  
74             }
75            
76             =item read_file( $file )
77            
78             Opens and reads the first few bytes of the file supplied (as either a filehandle or a path), uses them to start a new stream then calls parse_header.
79            
80             =cut
81            
82             sub read_file {
83 1     1 1 425 my ($self, $path) = @_;
84 1 50       4 return unless $path;
85 1         2 my $file;
86 1 50       5 if (ref($path)) {
87 0         0 $file = $path;
88             } else {
89 1 50       75 open( $file, $path ) or Carp::croak(1, "opening $path failed: $!");
90             }
91 1         3 binmode($file);
92 1         46 read($file, my $data, 4096);
93            
94 1 50       9 $self = $self->new() unless ref $self;
95 1         6 $self->new_stream($data);
96 1         136 return $self->parse_header;
97             }
98            
99             =item read_data( $string )
100            
101             Just for consistency. All this does is start a new stream with the data supplied and call parse_header.
102            
103             =cut
104            
105             sub read_data {
106 0     0 1 0 my ($self, $data) = @_;
107 0 0       0 return unless $data;
108            
109 0 0       0 $self = $self->new() unless ref $self;
110 0         0 $self->new_stream($data);
111 0         0 return $self->parse_header;
112             }
113            
114             =item parse_header( $string )
115            
116             Checks that this is a properly-formatted SWF file, then pulls the relevant bytes out of the header block of the file and returns a hashref containing the stage dimensions, coordinates, duration, frame rate, version and file size. In detail:
117            
118             {
119             signature => 'FWS' or 'CWS',
120             version => Shockwave language version,
121             filelen => Length of entire file in bytes,
122             xmin => Stage left edge, in twips,
123             xmax => Stage right edge, in twips from left,
124             ymin => Stage top edge,
125             ymax => Stage bottom edge, in twips from top,
126             rate => Frame rate in fps,
127             count => total number of frames in movie,
128             width => calculated width of stage (in pixels),
129             height => calculated height of stage (in pixels),
130             duration => calculated duration of movie (in seconds),
131             background => calculated background color of movie (in html format),
132             }
133            
134             =cut
135            
136             sub parse_header {
137 1     1 1 2 my ($self, $data) = @_;
138 1 50       5 $self->stream->add_stream($data) if $data;
139            
140 1         2 my $header = {};
141 1         4 $header->{signature} = $self->stream->get_string(3);
142 1 50 33     51 if ($header->{signature} ne 'CWS' && $header->{signature} ne 'FWS') {
143 0         0 Carp::carp "This is not an SWF stream ";
144 0         0 return;
145             }
146 1         5 $header->{version} = $self->{_version} = $self->stream->get_UI8;
147 1         33 $header->{filelen} = $self->stream->get_UI32;
148 1 50       35 $self->stream->add_codec('Zlib') if $header->{signature} eq 'CWS';
149            
150 1         75797 my $nbits = $self->stream->get_bits(5);
151 1         49 $header->{xmin} = $self->stream->get_sbits($nbits);
152 1         39 $header->{xmax} = $self->stream->get_sbits($nbits);
153 1         40 $header->{ymin} = $self->stream->get_sbits($nbits);
154 1         38 $header->{ymax} = $self->stream->get_sbits($nbits);
155 1         32 $header->{rate} = $self->stream->get_UI16 / 256;
156 1         32 $header->{count} = $self->stream->get_UI16;
157 1         31 $header->{width} = int(($header->{xmax} - $header->{xmin}) / 20);
158 1         6 $header->{height} = int(($header->{ymax} - $header->{ymin}) / 20);
159 1         3 $header->{duration} = $header->{count} / $header->{rate};
160            
161 1         3 my $temp = $self->stream->get_sbits($nbits);
162 1         38 my $background_r = $self->stream->get_UI8();
163 1         25 my $background_g = $self->stream->get_UI8();
164 1         22 my $background_b = $self->stream->get_UI8();
165 1         25 $header->{background} = sprintf ("#%02X%02X%02X", $background_r, $background_g, $background_b);
166            
167 1         43 return $header;
168             }
169            
170             =head1 COPYRIGHT
171            
172             Copyright 2004 William Ross (wross@cpan.org)
173            
174             But obviously based entirely on previous work by Yasuhiro Sasama.
175            
176             This library is free software; you can redistribute it
177             and/or modify it under the same terms as Perl itself.
178            
179             =head1 SEE ALSO
180            
181             L, L, L, L
182            
183             The SWF file format specification from Macromedia can be found at
184             http://www.openswf.org/spec/SWFfileformat.html
185            
186             =cut
187            
188             1;