File Coverage

blib/lib/File/Binary.pm
Criterion Covered Total %
statement 115 130 88.4
branch 26 44 59.0
condition 8 18 44.4
subroutine 30 32 93.7
pod 19 20 95.0
total 198 244 81.1


line stmt bran cond sub pod time code
1             package File::Binary;
2              
3             # importage
4 73     73   2000968 use strict;
  73         183  
  73         3447  
5 73     73   469 use Carp;
  73         142  
  73         7560  
6 73     73   436 use Config;
  73         137  
  73         2627  
7 73     73   76074 use IO::File;
  73         986973  
  73         11110  
8 73     73   658 use vars qw(@EXPORT_OK $VERSION $BIG_ENDIAN $LITTLE_ENDIAN $NATIVE_ENDIAN $AUTOLOAD $DEBUG);
  73         156  
  73         17593  
9 73     73   405 use Fcntl qw(:DEFAULT);
  73         154  
  73         199661  
10              
11             $VERSION='1.7';
12              
13             # for seekable stuff
14             $DEBUG = 0;
15              
16             # set up some constants
17             $BIG_ENDIAN = 2;
18             $LITTLE_ENDIAN = 1;
19             $NATIVE_ENDIAN = 0;
20              
21             # and export them
22             @EXPORT_OK = qw($BIG_ENDIAN $LITTLE_ENDIAN $NATIVE_ENDIAN guess_endian);
23              
24              
25             =head1 NAME
26              
27             File::Binary - Binary file reading module
28              
29             =head1 SYNOPSIS
30              
31             use File::Binary qw($BIG_ENDIAN $LITTLE_ENDIAN $NATIVE_ENDIAN);
32              
33             my $fb = File::Binary->new("myfile");
34            
35             $fb->get_ui8();
36             $fb->get_ui16();
37             $fb->get_ui32();
38             $fb->get_si8();
39             $fb->get_si16();
40             $fb->get_si32();
41              
42             $fb->close();
43              
44             $fb->open(">newfile");
45              
46             $fb->put_ui8(255);
47             $fb->put_ui16(65535);
48             $fb->put_ui32(4294967295);
49             $fb->put_si8(-127);
50             $fb->put_si16(-32767);
51             $fb->put_si32(-2147483645);
52            
53             $fb->close();
54              
55              
56             $fb->open(IO::Scalar->new($somedata));
57             $fb->set_endian($BIG_ENDIAN); # force endianness
58              
59             # do what they say on the tin
60             $fb->seek($pos);
61             $fb->tell();
62              
63             # etc etc
64              
65              
66             =head1 DESCRIPTION
67              
68             B is a Binary file reading module, hence the name,
69             and was originally used to write a suite of modules for manipulating
70             Macromedia SWF files.
71              
72             However it's grown beyond that and now actually, err, works.
73             And is generalised. And EVERYTHING! Yay!
74              
75             It has methods for reading and writing signed and unsigned 8, 16 and
76             32 bit integers, at some point in the future I'll figure out a way of
77             putting in methods for >32bit integers nicely but until then, patches
78             welcome.
79              
80             It hasn't retained backwards compatability with the old version of this
81             module for cleanliness sakes and also because the old interface was
82             pretty braindead.
83              
84             =head1 METHODS
85              
86             =head2 new
87              
88             Pass in either a file name or something which isa an IO::Handle.
89              
90             =cut
91              
92             sub new {
93 289     289 1 21593 my ($class, $file) = @_;
94              
95 289         984 my $self = {};
96            
97 289         2965 bless $self, $class;
98              
99 289         1350 $self->open($file);
100 289         1125 $self->set_endian($NATIVE_ENDIAN);
101              
102              
103 289         2587 return $self;
104             }
105              
106             =head2 open
107              
108             Pass in either a file name or something which isa an IO::Handle.
109              
110             Will try and set binmode for the handle on if possible (i.e
111             if the object has a C method) otherwise you should do
112             it yourself.
113              
114             =cut
115              
116             sub open {
117 289     289 1 813 my ($self, $file) = @_;
118            
119 289         508 my $fh;
120 289         509 my $writeable = -1;
121              
122 289 100 66     2778 if (ref($file) =~ /^IO::/ && $file->isa('IO::Handle')) {
123 72         200 $fh = $file;
124 72         190 $writeable = 2; # read and write mode
125             } else {
126 217   50     1880 $fh = IO::File->new($file) || die "No such file $file\n";
127 217 100       1171682 if ($file =~ /^>/) {
    50          
128 72         302 $writeable = 1;
129             } elsif ($file =~ /^\+>/) {
130 0         0 $writeable=2;
131             }
132             }
133 289 50       3629 $fh->binmode if $fh->can('binmode');
134              
135 289         2946 $self->{_bitbuf} = '';
136 289         712 $self->{_bitpos} = 0;
137 289         668 $self->{_fh} = $fh;
138 289         1064 $self->{_fhpos} = 0;
139 289         692 $self->{_flush} = 1;
140 289         646 $self->{_writeable} = $writeable;
141 289 100       2018 $self->{_is_seekable} = UNIVERSAL::isa($fh,'IO::Seekable')?1:0;
142            
143              
144 289         577 return $self;
145             }
146              
147             =head2 seek
148              
149             Seek to a position.
150              
151             Return our current position. If our file handle is not
152             B it will return 0 and, if
153             B<$File::Binary::DEBUG> is set to 1, there will be a warning.
154              
155             You can optionally pass a whence option in the same way as
156             the builtin Perl seek() method. It defaults to C.
157              
158             Returns the current file position.
159              
160              
161             =cut
162              
163             sub seek {
164 10     10 1 2585 my $self = shift;
165 10         12 my $seek = shift;
166 10   50     32 my $whence = shift || SEEK_SET;
167 10 50       19 unless ($self->{_is_seekable}) {
168 0 0       0 carp "FH is not seekable" if $DEBUG;
169 0         0 return 0;
170             }
171              
172 10 50       42 $self->{_fh}->seek($seek, $whence) if defined $seek;
173 10         169 $self->_init_bits();
174 10         24 return $self->{_fh}->tell();
175              
176              
177            
178             }
179              
180             =head2 tell
181              
182             Return our current position. If our file handle is not
183             B then it will return 0 and, if
184             B<$File::Binary::DEBUG> is set to 1, there will be a
185             warning.
186              
187             =cut
188              
189             sub tell {
190 10     10 1 38 my $self = shift;
191 10 50       22 unless ($self->{_is_seekable}) {
192 0 0       0 carp "FH is not seekable" if $DEBUG;
193 0         0 return 0;
194             }
195              
196 10         35 return $self->{_fh}->tell();
197             }
198              
199              
200              
201             =head2 set_flush
202              
203             To flush or not to flush. That is the question
204              
205             =cut
206              
207             sub set_flush {
208 0     0 1 0 my ($self, $flush) = @_;
209              
210 0         0 $self->{_flush} = $flush;
211             }
212              
213              
214             =head2 set_endian
215              
216             Set the how the module reads files. The options are
217              
218             $BIG_ENDIAN
219             $LITTLE_ENDIAN
220             $NATIVE_ENDIAN
221              
222              
223             I will deduce the endianess of the current system.
224              
225             =cut
226              
227             sub set_endian {
228 578     578 1 3493 my ($self, $endian) = @_;
229              
230 578   66     2252 $endian ||= $NATIVE_ENDIAN;
231              
232 578 100       1999 $endian = guess_endian() if ($endian == $NATIVE_ENDIAN);
233              
234 578 100       1466 if ($endian == $BIG_ENDIAN) {
235 144         1065 $self->{_ui16} = 'v';
236 144         280 $self->{_ui32} = 'V';
237             } else {
238 434         1391 $self->{_ui16} = 'n';
239 434         1017 $self->{_ui32} = 'N';
240             }
241              
242 578         1388 $self->{_endian} = $endian;
243              
244             }
245              
246              
247             sub _init_bits {
248 2904     2904   4518 my $self = shift;
249              
250 2904 50       6390 if ($self->{_writeable}) {
251 2904         6071 $self->_init_bits_write();
252             } else {
253 0         0 $self->_init_bits_read();
254             }
255             }
256              
257              
258             sub _init_bits_write {
259 2904     2904   3341 my $self = shift;
260              
261 2904         4370 my $bits = $self->{'_bitbuf'};
262              
263 2904         3943 my $len = length($bits);
264              
265 2904 50       10928 return if $len<=0;
266              
267 0         0 $self->{'_bitbuf'} = '';
268 0         0 $self->{_fh}->write(pack('B8', $bits.('0'x(8-$len))));
269              
270             }
271              
272             sub _init_bits_read {
273 0     0   0 my $self = shift;
274            
275 0         0 $self->{_pos} = 0;
276 0         0 $self->{_bits} = 0;
277              
278             }
279              
280              
281             =head2 get_bytes
282              
283             Get an arbitary number of bytes from the file.
284              
285             =cut
286              
287             sub get_bytes {
288 2894     2894 1 3800 my ($self, $bytes) = @_;
289            
290 2894         3457 $bytes = int $bytes;
291              
292 2894 50       8247 carp("Must be positive number") if ($bytes <1);
293 2894 50       6777 carp("This file has been opened in write mode.") if $self->{_writeable} == 1;
294              
295 2894 50       9989 $self->_init_bits() if $self->{_flush};
296            
297 2894         12584 $self->{_fh}->read(my $data, $bytes);
298              
299 2894         1364887 $self->{_fhpos} += $bytes;
300              
301 2894         19219 return $data;
302             }
303            
304              
305             =head2 put_bytes
306              
307             Write some bytes
308              
309             =cut
310              
311             sub put_bytes {
312 958     958 1 1449 my ($self, $bytes) = @_;
313              
314            
315 958 50       2361 carp("This file has been opened in read mode.") unless $self->{_writeable};
316              
317             ## TODO?
318             #$self->_init_bits;
319 958         5228 $self->{_fh}->write($bytes);
320             }
321              
322              
323              
324              
325             # we could use POSIX::ceil here but I ph34r the POSIX lib
326             sub _round {
327 958   50 958   2936 my $num = shift || 0;
328              
329 958         6078 return int ($num + 0.5 * ($num <=> 0 ) );
330             }
331              
332              
333              
334              
335              
336             sub _get_num {
337 2894     2894   5250 my ($self, $bytes, $template)=@_;
338              
339 2894         6881 unpack $template, $self->get_bytes($bytes);
340             }
341              
342              
343             sub _put_num {
344 958     958   1469 my ($self, $num, $template) = @_;
345              
346              
347 958         2568 $self->put_bytes(pack($template, _round($num)));
348             }
349              
350              
351              
352             ## 8 bit
353              
354             =head2 get_ui8 get_si8 put_ui8 put_si8
355              
356             read or write signed or unsigned 8 bit integers
357              
358             =cut
359              
360             sub get_ui8 {
361 162     162 1 471 my $self = shift;
362 162         457 $self->_get_num(1, 'C');
363             }
364              
365              
366              
367              
368             sub get_si8 {
369 288     288 1 904 my $self = shift;
370 288         838 $self->_get_num(1, 'c');
371             }
372              
373              
374              
375             sub put_ui8 {
376 54     54 1 24034 my ($self,$num) = @_;
377 54         406 $self->_put_num($num, 'C');
378             }
379              
380              
381             sub put_si8 {
382 96     96 1 47195 my ($self,$num) = @_;
383 96         268 $self->_put_num($num, 'c');
384              
385             }
386              
387              
388             ## 16 bit
389              
390             =head2 get_ui16 get_si16 put_ui16 put_si16
391              
392             read or write signed or unsigned 16 bit integers
393              
394             =cut
395              
396             sub get_ui16 {
397 828     828 1 2001 my $self = shift;
398 828         2377 $self->_get_num(2, $self->{_ui16});
399             }
400              
401              
402             sub get_si16 {
403 540     540 1 1552 my $self = shift;
404            
405 540         1207 my $num = $self->get_ui16();
406 540 100       1491 $num -= (1<<16) if $num>=(1<<15);
407              
408 540         2554 return $num;
409             }
410              
411              
412              
413             sub put_ui16 {
414 276     276 1 102004 my ($self,$num) = @_;
415            
416 276         1187 $self->_put_num($num, $self->{_ui16});
417             }
418              
419             *put_si16 = \&put_ui16;
420              
421              
422              
423             ## 32 bit
424              
425             =head2 get_ui32 get_s32 put_ui32 put_si32
426              
427             read or write signed or unsigned 32 bit integers
428              
429             =cut
430              
431              
432              
433             sub get_ui32 {
434 1616     1616 1 2474 my $self = shift;
435 1616         4847 return $self->_get_num(4, $self->{_ui32});
436             }
437              
438              
439             sub get_si32 {
440 1076     1076 0 2369 my $self = shift;
441              
442 1076         2418 my $num = $self->get_ui32();
443 1076 100       2976 $num -= (2**32) if ($num>=(2**31));
444 1076         4482 return $num;
445             }
446              
447              
448             sub put_ui32 {
449 532     532 1 228919 my ($self, $num) = @_;
450              
451 532         1593 $self->_put_num($num, $self->{_ui32});
452             }
453              
454             *put_si32 = \&put_ui32;
455              
456              
457              
458              
459             =head2 guess_endian
460              
461             Guess the endianness of this system. Returns either I<$LITTLE_ENDIAN>
462             or I<$BIG_ENDIAN>
463              
464             =cut
465              
466             sub guess_endian {
467              
468              
469             #my $svalue = int rand (2**16)-1;
470             #my $lvalue = int rand (2**32)-1;
471              
472             #my $sp = pack("S", $svalue);
473             #my $lp = pack("L", $lvalue);
474              
475              
476             #if (unpack("V", $lp) == $lvalue && unpack("v", $sp) == $svalue) {
477             # return $LITTLE_ENDIAN;
478             #} elsif (unpack("N", $lp) == $lvalue && unpack("n", $sp) == $svalue) {
479             # return $BIG_ENDIAN;
480             #} else {
481             # carp "Couldn't determine whether this machine is big-endian or little-endian\n";
482             #}
483              
484 289     289 1 86856 my $bo = $Config{'byteorder'};
485              
486 289 50 33     278923 if (1234 == $bo or 12345678 == $bo) {
    0 0        
487 289         868 return $LITTLE_ENDIAN;
488             } elsif (4321 == $bo or 87654321 == $bo) {
489 0         0 return $BIG_ENDIAN;
490             } else {
491 0         0 carp "Unsupported architecture (probably a Cray or weird order)\n";
492             }
493              
494              
495             }
496              
497              
498             =head2 close
499            
500             Close the file up. The I object will then be useless
501             until you open up another file;
502              
503             =cut
504              
505             sub close {
506 289     289 1 30387 my $self = shift;
507 289         2362 $self->{_fh}->close();
508 289         14268 $self = {};
509             }
510              
511              
512              
513             =pod
514              
515             =head1 BUGS
516              
517             Can't do numbers greater than 32 bits.
518              
519             Can't extract Floating Point or Fixed Point numbers.
520              
521             Can't extract null terminated strings.
522              
523             Needs tests for seeking and telling.
524              
525             =head1 COPYING
526              
527             (c)opyright 2002, Simon Wistow
528              
529             Distributed under the same terms as Perl itself.
530              
531             This software is under no warranty and will probably ruin your life, kill your friends, burn your house and bring about the apocalypse
532              
533              
534             =head1 AUTHOR
535              
536             Copyright 2003, Simon Wistow
537              
538              
539             =cut
540              
541              
542             1;