File Coverage

blib/lib/File/Format/RIFF/Chunk.pm
Criterion Covered Total %
statement 73 81 90.1
branch 16 28 57.1
condition 1 9 11.1
subroutine 22 23 95.6
pod 6 8 75.0
total 118 149 79.1


line stmt bran cond sub pod time code
1             package File::Format::RIFF::Chunk;
2              
3              
4             our $VERSION = '0.09';
5              
6              
7 3     3   3898 use bytes;
  3         34  
  3         14  
8 3     3   80 use Carp;
  3         6  
  3         209  
9              
10              
11 3     3   16 use vars qw/ $PACKFMT /;
  3         5  
  3         331  
12 3     3   4886 BEGIN { $PACKFMT = 'V' }
13              
14              
15             sub new
16             {
17 15     15 1 144 my ( $proto, $id, $data ) = @_;
18 15         50 my ( $self ) = $proto->_new;
19 15 100       77 $self->id( defined $id ? $id : ' ' );
20 15         45 $self->data( $data );
21 15         41 return $self;
22             }
23              
24              
25             sub _new
26             {
27 18     18   30 my ( $proto ) = @_;
28 18   33     93 my ( $class ) = ref( $proto ) || $proto;
29 18         64 return bless { }, $class;
30             }
31              
32              
33             sub write
34             {
35 6     6 0 2052 my ( $self, $fh ) = @_;
36 6         45 $self->_write_header( $fh );
37 6         18 $self->_write_data( $fh );
38             }
39              
40              
41             sub id
42             {
43 30     30 1 58 my ( $self ) = shift;
44 30 100       138 return $self->{id} unless ( @_ );
45 20         30 my ( $id ) = shift;
46 20 50       43 croak "Length of id must be 4" unless ( length( $id ) == 4 );
47 20         62 $self->{id} = $id;
48             }
49              
50              
51             sub data
52             {
53 26     26 1 45 my ( $self ) = shift;
54 26 100       105 return $self->{data} unless ( @_ );
55 13         22 my ( $data ) = shift;
56 13 100       34 $data = '' unless ( defined $data );
57 13         35 $self->{size} = length( $self->{data} = $data );
58             }
59              
60              
61             sub size
62             {
63 23     23 1 28 my ( $self ) = @_;
64 23         51 return $self->{size};
65             }
66              
67              
68             sub total_size
69             {
70 28     28 1 42 my ( $self ) = @_;
71 28         81 my ( $sz ) = $self->size;
72 28         99 return 8 + $sz + ( $sz % 2 );
73             }
74              
75              
76             sub _read_header
77             {
78 4     4   5 my ( $self, $fh ) = @_;
79 4         15 $self->{size} = $self->_read_size( $fh );
80             }
81              
82              
83             sub _write_header
84             {
85 3     3   3 my ( $self, $fh ) = @_;
86 3         7 $self->_write_fourcc( $fh, $self->{id} );
87 3         5 $self->_write_size( $fh, $self->{size} );
88             }
89              
90              
91             sub _read_data
92             {
93 2     2   3 my ( $self, $fh ) = @_;
94 2         6 my ( $sz ) = $self->size;
95 2         7 $self->_file_read( $fh, \$self->{data}, $sz );
96 2 50       8 return unless ( $sz % 2 );
97              
98 0         0 my ( $x );
99 0         0 $self->_file_read( $fh, \$x, 1 );
100             }
101              
102              
103             sub _write_data
104             {
105 3     3   3 my ( $self, $fh ) = @_;
106 3         6 $self->_file_write( $fh, $self->{data} );
107 3 50       12 $self->_file_write( $fh, "\0" ) if ( $self->{size} % 2 );
108             }
109              
110              
111             sub _file_read
112             {
113 12     12   16 my ( $proto, $fh, $ref, $expect ) = @_;
114 12         44 my ( $got ) = read( $fh, $$ref, $expect );
115 12 50       27 croak "File read error: $!" unless ( defined $got );
116 12 50       26 croak "File read error: expected $expect bytes, got $got"
117             unless ( $got == $expect );
118             }
119              
120              
121             sub _file_write
122             {
123 18     18   30 my ( $proto, $fh, @data ) = @_;
124 18 50       16 print { $fh } @data or croak 'Could not write to file';
  18         60  
125             }
126              
127              
128             sub _read_fourcc
129             {
130 6     6   8 my ( $proto, $fh ) = @_;
131 6         6 my ( $fourcc );
132 6         19 $proto->_file_read( $fh, \$fourcc, 4 );
133 6         18 return $fourcc;
134             }
135              
136              
137             sub _write_fourcc
138             {
139 9     9   11 my ( $self, $fh, $fourcc ) = @_;
140 9         20 $self->_file_write( $fh, $fourcc );
141             }
142              
143              
144             sub _read_size
145             {
146 4     4   5 my ( $proto, $fh ) = @_;
147 4         4 my ( $size );
148 4         8 $proto->_file_read( $fh, \$size, 4 );
149 4         15 return unpack( $PACKFMT, $size );
150             }
151              
152              
153             sub _write_size
154             {
155 6     6   8 my ( $self, $fh, $size ) = @_;
156 6         24 $self->_file_write( $fh, pack( $PACKFMT, $size ) );
157             }
158              
159              
160             sub dump
161             {
162 0     0 1 0 my ( $self, $max, $indent ) = @_;
163 0 0       0 $max = 64 unless ( defined $max );
164 0 0 0     0 $indent = 0 unless ( defined $indent and $indent > 0 );
165 0         0 print join( '', "\t" x $indent ), 'id: ', $self->id,
166             ' size: ', $self->size, ' (', $self->total_size, '): ';
167 0 0 0     0 ( $max and $self->size > $max ) ? print '[...]' : print $self->{data};
168 0         0 print "\n";
169             }
170              
171              
172             sub read
173             {
174 4     4 0 7 my ( $proto, $id, $fh ) = @_;
175 4 100       19 my ( $self ) = ref( $proto ) ? $proto : $proto->_new;
176 4         12 $self->id( $id );
177 4         19 $self->_read_header( $fh );
178 4         16 $self->_read_data( $fh );
179 4         11 return $self;
180             }
181              
182              
183             1;
184              
185              
186             =pod
187              
188             =head1 NAME
189              
190             File::Format::RIFF::Chunk - a single RIFF chunk
191              
192             =head1 SYNOPSIS
193              
194             use File::Format::RIFF;
195              
196             my ( $chunk ) = new File::Format::RIFF::Chunk;
197             $chunk->id( 'stuf' );
198             $chunk->data( 'here is some stuff' );
199              
200             ... some $container ...
201              
202             $container->push( $chunk );
203              
204             =head1 DESCRIPTION
205              
206             A C is a single chunk of data in a RIFF file. It
207             has an identifier and one piece of scalar data. The id must be a
208             four character code, and the data can be any piece of scalar data you wish
209             to store, in any format (it is treated as opaque binary data, so you must
210             interpret it yourself).
211              
212             =head1 CONSTRUCTOR
213              
214             =over 4
215              
216             =item $chunk = new File::Format::RIFF::Chunk( $id, $data );
217              
218             Creates a new File::Format::RIFF::Chunk object. C<$id> is a four character
219             code that identifies the type of data. If C<$id> is not specified, it
220             defaults to C<' '> (four spaces). C<$data> is a scalar, treated as
221             opaque binary data. If C<$data> is C or not specified, it defaults
222             to ''.
223              
224             =back
225              
226             =head1 METHODS
227              
228             =over 4
229              
230             =item $id = $chunk->id;
231              
232             Returns the id of C<$chunk>.
233              
234             =item $chunk->id( 'abcd' );
235              
236             Sets the id of C<$chunk>. C<$id> must be a four character code that
237             identifies the type of data.
238              
239             =item $data = $chunk->data;
240              
241             Returns the data of C<$chunk>.
242              
243             =item $chunk->data( $data );
244              
245             Sets the data of C<$chunk>. C<$data> is treated as a piece of opaque
246             binary data, not modified or interpreted in any way.
247              
248             =item $size = $chunk->size;
249              
250             Returns the size (in bytes) of C<$chunk>'s data.
251              
252             =item $total_size = $chunk->total_size;
253              
254             Returns the total size (in bytes) that C<$chunk> will take up when written
255             out to a file. Total size is the size of the data, plus 8 bytes for the
256             header, plus 1 alignment byte if the data has an odd number of bytes (so that
257             the RIFF chunks will be word-aligned on disk).
258              
259             =item $chunk->dump( $max );
260              
261             Prints a string representation of C<$chunk> to STDOUT. If the data is
262             larger than C<$max> bytes, prints '[...]' instead of the actual data. If
263             C<$max> is not specified or C, it defaults to 64.
264              
265             A RIFF chunk is rendered as:
266              
267             id: EidE size: EsizeE (Etotal sizeE): EdataE
268              
269             =back
270              
271             =head1 AUTHOR
272              
273             Paul Sturm EIE
274              
275             =cut