File Coverage

blib/lib/File/Format/RIFF/Container.pm
Criterion Covered Total %
statement 91 100 91.0
branch 22 32 68.7
condition 5 12 41.6
subroutine 23 24 95.8
pod 16 17 94.1
total 157 185 84.8


line stmt bran cond sub pod time code
1             package File::Format::RIFF::Container;
2 3     3   21 use base File::Format::RIFF::Chunk;
  3         7  
  3         2530  
3              
4              
5             our $VERSION = '0.08';
6              
7              
8 3     3   22 use Carp;
  3         9  
  3         244  
9 3     3   2903 use File::Format::RIFF::List;
  3         28  
  3         4405  
10              
11              
12             sub new
13             {
14 4     4 1 11 my ( $proto, $type, $id, $data ) = @_;
15 4         28 my ( $self ) = $proto->SUPER::new( $id, $data );
16 4 100       26 $self->type( defined $type ? $type : ' ' );
17 4         10 return $self;
18             }
19              
20              
21             sub type
22             {
23 16     16 1 51 my ( $self ) = shift;
24 16 100       64 return $self->{type} unless ( @_ );
25 7         12 my ( $type ) = shift;
26 7 50       17 croak "Length of type must be 4" unless ( length( $type ) == 4 );
27 7         17 $self->{type} = $type;
28             }
29              
30              
31             sub id
32             {
33 8     8 1 20 my ( $self ) = shift;
34 8 50 66     59 croak "Cannot set id of $self->{id} chunk" if ( @_ and exists $self->{id} );
35 8         36 return $self->SUPER::id( @_ );
36             }
37              
38              
39             sub read
40             {
41 2     2 0 4 my ( $proto ) = shift;
42 2 100       22 delete $proto->{id} if ( ref( $proto ) );
43 2         12 return $proto->SUPER::read( @_ );
44             }
45              
46              
47             sub total_size
48             {
49 9     9 1 19 my ( $self ) = @_;
50 9         40 return $self->SUPER::total_size + 4;
51             }
52              
53              
54             sub data
55             {
56 7     7 1 135 my ( $self ) = shift;
57 7 100       30 return @{ $self->{data} } unless ( @_ );
  2         9  
58 5         10 my ( $data ) = @_;
59 5 100 66     42 $data = [ ] unless ( defined $data and ref( $data ) eq 'ARRAY' );
60 5         504 $self->{data} = [ ];
61 5         33 $self->push( @$data );
62             }
63              
64              
65             sub numChunks
66             {
67 6     6 1 21 my ( $self ) = @_;
68 6         8 return scalar( @{ $self->{data} } );
  6         26  
69             }
70              
71              
72             sub size
73             {
74 15     15 1 28 my ( $self ) = @_;
75 15         18 my ( $sz ) = 0;
76 15         17 map { $sz += $_->total_size } @{ $self->{data} };
  19         50  
  15         32  
77 15         51 return $sz;
78             }
79              
80              
81             sub splice
82             {
83 17     17 1 38 my ( $self, $offset, $length, @elts ) = @_;
84 17 50 33     23 map { croak "Can only add Chunk or List elements"
  15         141  
85             unless ( ref( $_ ) and $_->isa( 'File::Format::RIFF::Chunk' ) ) } @elts;
86 12         57 return ( @_ > 3 )
87 4         17 ? splice( @{ $self->{data} }, $offset, $length, @elts )
88             : ( @_ == 3 )
89 1         4 ? splice( @{ $self->{data} }, $offset, $length )
90             : ( @_ == 2 )
91 0         0 ? splice( @{ $self->{data} }, $offset )
92 17 50       53 : splice( @{ $self->{data} } );
    100          
    100          
93             }
94              
95              
96             sub push
97             {
98 12     12 1 25 my ( $self, @elts ) = @_;
99 12         15 return $self->splice( scalar( @{ $self->{data} } ), 0, @elts );
  12         54  
100             }
101              
102              
103             sub pop
104             {
105 1     1 1 2 my ( $self ) = @_;
106 1         3 return $self->splice( -1 );
107             }
108              
109              
110             sub unshift
111             {
112 1     1 1 3 my ( $self, @elts ) = @_;
113 1         3 return $self->splice( 0, 0, @elts );
114             }
115              
116              
117             sub at
118             {
119 14     14 1 28 my ( $self ) = shift;
120 14         17 my ( $i ) = shift;
121 14 100       49 return $self->splice( $i, 1, shift ) if ( @_ );
122 13         63 return $self->{data}->[ $i ];
123             }
124              
125              
126             sub addChunk
127             {
128 3     3 1 14 my ( $self ) = shift;
129 3         24 my ( $chk ) = new File::Format::RIFF::Chunk( @_ );
130 3         9 $self->push( $chk );
131 3         6 return $chk;
132             }
133              
134              
135             sub addList
136             {
137 1     1 1 14 my ( $self ) = shift;
138 1         6 my ( $ctr ) = new File::Format::RIFF::List( @_ );
139 1         3 $self->push( $ctr );
140 1         3 return $ctr;
141             }
142              
143              
144             sub _read_header
145             {
146 2     2   3 my ( $self, $fh ) = @_;
147 2         10 $self->SUPER::_read_header( $fh );
148 2         3 $self->{size} -= 4;
149 2         6 $self->{type} = $self->_read_fourcc( $fh );
150             }
151              
152              
153             sub _write_header
154             {
155 3     3   3 my ( $self, $fh ) = @_;
156 3         13 $self->_write_fourcc( $fh, $self->{id} );
157 3         7 $self->_write_size( $fh, $self->size + 4 );
158 3         9 $self->_write_fourcc( $fh, $self->{type} );
159             }
160              
161              
162             sub _read_data
163             {
164 2     2   3 my ( $self, $fh ) = @_;
165 2         5 my ( $to_read ) = $self->{size};
166 2         4 $self->{data} = [ ];
167 2         6 while ( $to_read )
168             {
169 2         12 my ( $id ) = $self->_read_fourcc( $fh );
170 2 50       5 croak "Embedded RIFF chunks not allowed" if ( $id eq 'RIFF' );
171 2 50       14 my ( $subchunk ) = ( $id eq 'LIST' )
172             ? File::Format::RIFF::List->read( $fh )
173             : File::Format::RIFF::Chunk->read( $id, $fh );
174 2         7 $to_read -= $subchunk->total_size;
175 2         10 $self->push( $subchunk );
176             }
177             }
178              
179              
180             sub _write_data
181             {
182 3     3   4 my ( $self, $fh ) = @_;
183 3         3 map { $_->write( $fh ) } @{ $self->{data} };
  3         9  
  3         5  
184             }
185              
186              
187             sub dump
188             {
189 0     0 1 0 my ( $self, $max, $indent ) = @_;
190 0 0       0 $max = 64 unless ( defined $max );
191 0 0 0     0 $indent = 0 unless ( defined $indent and $indent > 0 );
192 0         0 print join( '', "\t" x $indent ), 'id: ', $self->id, ' (',
193             $self->type, ') size: ', $self->size, ' (', $self->total_size, ")\n";
194              
195 0         0 ++ $indent;
196 0         0 map { $_->dump( $max, $indent ) } @{ $self->{data} };
  0         0  
  0         0  
197             }
198              
199              
200             sub shift
201             {
202 1     1 1 3 my ( $self ) = @_;
203 1         3 return $self->splice( 0, 1 );
204             }
205              
206              
207             1;
208              
209              
210             =pod
211              
212             =head1 NAME
213              
214             File::Format::RIFF::Container - RIFF Container (Lists and RIFFs)
215              
216             =head1 SYNOPSIS
217              
218             You should not instantiate a C directly;
219             instead, you should instantiate one of its subclasses: either a
220             L object, or a L object.
221              
222             =head1 DESCRIPTION
223              
224             C is a base class for both RIFF objects
225             and RIFF lists. It is, essentially, an array of other RIFF lists and/or
226             RIFF chunks, and you can add, change, delete, and read them.
227              
228             =head1 METHODS
229              
230             =over 4
231              
232             =item $type = $container->type;
233              
234             Returns the type of C<$container>.
235              
236             =item $container->type( $type );
237              
238             Sets the type of C<$container>. C<$type> must be a four character code, which
239             represents what data will be found in C<$container>.
240              
241             =item $id = $container->id;
242              
243             Returns the id of C<$container>. C<$container> must be either a RIFF object
244             or a List object, so C<$id> will be 'RIFF' or 'LIST', respectively.
245              
246             =item @data = $container->data;
247              
248             Returns the RIFF chunks and/or RIFF lists contained by C<$container>.
249              
250             =item $container->data( $data );
251              
252             Clears out any existing RIFF chunks contained by C<$container> and replaces
253             them with C<$data>. C<$data> must be an array reference containing some
254             number of RIFF lists and/or RIFF chunks.
255              
256             =item $numChunks = $container->numChunks;
257              
258             Returns the number of RIFF lists and/or RIFF chunks contained by
259             C<$container>.
260              
261             =item $size = $container->size;
262              
263             Returns the size (in bytes) of C<$container>'s data, when written to a file.
264              
265             =item $total_size = $container->total_size;
266              
267             Returns the total size (in bytes) that C<$container> will take up when
268             written out to a file. Total size is the size of the data, plus 12 bytes
269             for the header.
270              
271             =item @replaced = $self->splice( $offset, $length, @list );
272              
273             =item $container->push( @chunks );
274              
275             =item $chunk = $container->pop;
276              
277             =item $container->unshift( @chunks );
278              
279             =item $chunk = $container->shift;
280              
281             C, C, C, C, and C operate analogously
282             to the same-named functions in core perl, acting on C<$container>'s array
283             of RIFF lists and/or RIFF chunks. All items added must be RIFF lists or
284             RIFF chunks.
285              
286             =item $chunk = $container->at( $i );
287              
288             Returns the RIFF list or RIFF chunk at the C<$i>th position in
289             C<$container>'s array.
290              
291             =item $container->at( $i, $chunk );
292              
293             Sets the C<$i>th position in C<$container>'s array to C<$chunk>, replacing
294             the previous item. C<$chunk> must be a RIFF list or a RIFF chunk.
295              
296             =item $newChunk = $container->addChunk( $id, $data );
297              
298             Creates a new RIFF chunk object with the given C<$id> and C<$data>, appending
299             it to C<$container>'s array. Returns the just-created RIFF chunk.
300              
301             =item $newList = $container->addList( $type, $data );
302              
303             Creates a new List object with the given C<$type> and C<$data>, appending
304             it to C<$container>'s array. Returns the just-created RIFF list.
305              
306             =item $container->dump( $max );
307              
308             Prints a string representation of C<$container> to STDOUT, recursively
309             printing contained items. If a RIFF chunk's data is larger than C<$max> bytes,
310             prints '[...]' instead of the actual data. If C<$max> is not specified or
311             C, it defaults to 64.
312              
313             A RIFF chunk is rendered as:
314              
315             id: EidE size: EsizeE (Etotal sizeE): EdataE
316              
317             A RIFF container is rendered as:
318              
319             id: EidE (EtypeE) size: EsizeE (Etotal sizeE)
320              
321             Items contained in the RIFF list are recursively printed on subsequent lines,
322             and are indented in one additional tab level.
323              
324             =back
325              
326             =head1 SEE ALSO
327              
328             =over 4
329              
330             =item L
331              
332             =item L
333              
334             =back
335              
336             =head1 AUTHOR
337              
338             Paul Sturm EIE
339              
340             =cut