File Coverage

blib/lib/IO/Zlib.pm
Criterion Covered Total %
statement 103 178 57.8
branch 31 78 39.7
condition 5 19 26.3
subroutine 22 36 61.1
pod 10 16 62.5
total 171 327 52.2


line stmt bran cond sub pod time code
1             # IO::Zlib.pm
2             #
3             # Copyright (c) 1998-2004 Tom Hughes .
4             # All rights reserved. This program is free software; you can redistribute
5             # it and/or modify it under the same terms as Perl itself.
6              
7             package IO::Zlib;
8              
9             =head1 NAME
10              
11             IO::Zlib - IO:: style interface to L
12              
13             =head1 SYNOPSIS
14              
15             With any version of Perl 5 you can use the basic OO interface:
16              
17             use IO::Zlib;
18              
19             $fh = new IO::Zlib;
20             if ($fh->open("file.gz", "rb")) {
21             print <$fh>;
22             $fh->close;
23             }
24              
25             $fh = IO::Zlib->new("file.gz", "wb9");
26             if (defined $fh) {
27             print $fh "bar\n";
28             $fh->close;
29             }
30              
31             $fh = IO::Zlib->new("file.gz", "rb");
32             if (defined $fh) {
33             print <$fh>;
34             undef $fh; # automatically closes the file
35             }
36              
37             With Perl 5.004 you can also use the TIEHANDLE interface to access
38             compressed files just like ordinary files:
39              
40             use IO::Zlib;
41              
42             tie *FILE, 'IO::Zlib', "file.gz", "wb";
43             print FILE "line 1\nline2\n";
44              
45             tie *FILE, 'IO::Zlib', "file.gz", "rb";
46             while () { print "LINE: ", $_ };
47              
48             =head1 DESCRIPTION
49              
50             C provides an IO:: style interface to L and
51             hence to gzip/zlib compressed files. It provides many of the same methods
52             as the L interface.
53              
54             Starting from IO::Zlib version 1.02, IO::Zlib can also use an
55             external F command. The default behaviour is to try to use
56             an external F if no C can be loaded, unless
57             explicitly disabled by
58              
59             use IO::Zlib qw(:gzip_external 0);
60              
61             If explicitly enabled by
62              
63             use IO::Zlib qw(:gzip_external 1);
64              
65             then the external F is used B of C.
66              
67             =head1 CONSTRUCTOR
68              
69             =over 4
70              
71             =item new ( [ARGS] )
72              
73             Creates an C object. If it receives any parameters, they are
74             passed to the method C; if the open fails, the object is destroyed.
75             Otherwise, it is returned to the caller.
76              
77             =back
78              
79             =head1 OBJECT METHODS
80              
81             =over 4
82              
83             =item open ( FILENAME, MODE )
84              
85             C takes two arguments. The first is the name of the file to open
86             and the second is the open mode. The mode can be anything acceptable to
87             L and by extension anything acceptable to I (that
88             basically means POSIX fopen() style mode strings plus an optional number
89             to indicate the compression level).
90              
91             =item opened
92              
93             Returns true if the object currently refers to a opened file.
94              
95             =item close
96              
97             Close the file associated with the object and disassociate
98             the file from the handle.
99             Done automatically on destroy.
100              
101             =item getc
102              
103             Return the next character from the file, or undef if none remain.
104              
105             =item getline
106              
107             Return the next line from the file, or undef on end of string.
108             Can safely be called in an array context.
109             Currently ignores $/ ($INPUT_RECORD_SEPARATOR or $RS when L
110             is in use) and treats lines as delimited by "\n".
111              
112             =item getlines
113              
114             Get all remaining lines from the file.
115             It will croak() if accidentally called in a scalar context.
116              
117             =item print ( ARGS... )
118              
119             Print ARGS to the file.
120              
121             =item read ( BUF, NBYTES, [OFFSET] )
122              
123             Read some bytes from the file.
124             Returns the number of bytes actually read, 0 on end-of-file, undef on error.
125              
126             =item eof
127              
128             Returns true if the handle is currently positioned at end of file?
129              
130             =item seek ( OFFSET, WHENCE )
131              
132             Seek to a given position in the stream.
133             Not yet supported.
134              
135             =item tell
136              
137             Return the current position in the stream, as a numeric offset.
138             Not yet supported.
139              
140             =item setpos ( POS )
141              
142             Set the current position, using the opaque value returned by C.
143             Not yet supported.
144              
145             =item getpos ( POS )
146              
147             Return the current position in the string, as an opaque object.
148             Not yet supported.
149              
150             =back
151              
152             =head1 USING THE EXTERNAL GZIP
153              
154             If the external F is used, the following Cs are used:
155              
156             open(FH, "gzip -dc $filename |") # for read opens
157             open(FH, " | gzip > $filename") # for write opens
158              
159             You can modify the 'commands' for example to hardwire
160             an absolute path by e.g.
161              
162             use IO::Zlib ':gzip_read_open' => '/some/where/gunzip -c %s |';
163             use IO::Zlib ':gzip_write_open' => '| /some/where/gzip.exe > %s';
164              
165             The C<%s> is expanded to be the filename (C is used, so be
166             careful to escape any other C<%> signs). The 'commands' are checked
167             for sanity - they must contain the C<%s>, and the read open must end
168             with the pipe sign, and the write open must begin with the pipe sign.
169              
170             =head1 CLASS METHODS
171              
172             =over 4
173              
174             =item has_Compress_Zlib
175              
176             Returns true if C is available. Note that this does
177             not mean that C is being used: see L
178             and L.
179              
180             =item gzip_external
181              
182             Undef if an external F B be used if C is
183             not available (see L), true if an external F
184             is explicitly used, false if an external F must not be used.
185             See L.
186              
187             =item gzip_used
188              
189             True if an external F is being used, false if not.
190              
191             =item gzip_read_open
192              
193             Return the 'command' being used for opening a file for reading using an
194             external F.
195              
196             =item gzip_write_open
197              
198             Return the 'command' being used for opening a file for writing using an
199             external F.
200              
201             =back
202              
203             =head1 DIAGNOSTICS
204              
205             =over 4
206              
207             =item IO::Zlib::getlines: must be called in list context
208              
209             If you want read lines, you must read in list context.
210              
211             =item IO::Zlib::gzopen_external: mode '...' is illegal
212              
213             Use only modes 'rb' or 'wb' or /wb[1-9]/.
214              
215             =item IO::Zlib::import: '...' is illegal
216              
217             The known import symbols are the C<:gzip_external>, C<:gzip_read_open>,
218             and C<:gzip_write_open>. Anything else is not recognized.
219              
220             =item IO::Zlib::import: ':gzip_external' requires an argument
221              
222             The C<:gzip_external> requires one boolean argument.
223              
224             =item IO::Zlib::import: 'gzip_read_open' requires an argument
225              
226             The C<:gzip_external> requires one string argument.
227              
228             =item IO::Zlib::import: 'gzip_read' '...' is illegal
229              
230             The C<:gzip_read_open> argument must end with the pipe sign (|)
231             and have the C<%s> for the filename. See L.
232              
233             =item IO::Zlib::import: 'gzip_write_open' requires an argument
234              
235             The C<:gzip_external> requires one string argument.
236              
237             =item IO::Zlib::import: 'gzip_write_open' '...' is illegal
238              
239             The C<:gzip_write_open> argument must begin with the pipe sign (|)
240             and have the C<%s> for the filename. An output redirect (>) is also
241             often a good idea, depending on your operating system shell syntax.
242             See L.
243              
244             =item IO::Zlib::import: no Compress::Zlib and no external gzip
245              
246             Given that we failed to load C and that the use of
247             an external F was disabled, IO::Zlib has not much chance of working.
248              
249             =item IO::Zlib::open: needs a filename
250              
251             No filename, no open.
252              
253             =item IO::Zlib::READ: NBYTES must be specified
254              
255             We must know how much to read.
256              
257             =item IO::Zlib::WRITE: too long LENGTH
258              
259             The LENGTH must be less than or equal to the buffer size.
260              
261             =back
262              
263             =head1 SEE ALSO
264              
265             L,
266             L,
267             L,
268             L
269              
270             =head1 HISTORY
271              
272             Created by Tom Hughes EFE.
273              
274             Support for external gzip added by Jarkko Hietaniemi EFE.
275              
276             =head1 COPYRIGHT
277              
278             Copyright (c) 1998-2004 Tom Hughes EFE.
279             All rights reserved. This program is free software; you can redistribute
280             it and/or modify it under the same terms as Perl itself.
281              
282             =cut
283              
284             require 5.006;
285              
286 9     9   4887 use strict;
  9         54  
  9         256  
287 9     9   43 use warnings;
  9         17  
  9         204  
288              
289 9     9   49 use Carp;
  9         15  
  9         798  
290 9     9   57 use Fcntl qw(SEEK_SET);
  9         14  
  9         342  
291 9     9   4299 use Symbol;
  9         7902  
  9         595  
292 9     9   3965 use Tie::Handle;
  9         17581  
  9         906  
293              
294             our $VERSION = "1.13";
295             our $AUTOLOAD;
296             our @ISA = qw(Tie::Handle);
297              
298             my $has_Compress_Zlib;
299             my $gzip_external;
300             my $gzip_used;
301             my $gzip_read_open = "gzip -dc %s |";
302             my $gzip_write_open = "| gzip > %s";
303             my $aliased;
304              
305             BEGIN {
306 9     9   32 eval { require Compress::Zlib };
  9         5846  
307 9 50 33     609807 $has_Compress_Zlib = $@ || $Compress::Zlib::VERSION < 2.000 ? 0 : 1;
308             }
309              
310             sub has_Compress_Zlib
311             {
312 0     0 1 0 $has_Compress_Zlib;
313             }
314              
315             sub gzip_external
316             {
317 0     0 1 0 $gzip_external;
318             }
319              
320             sub gzip_used
321             {
322 0     0 1 0 $gzip_used;
323             }
324              
325             sub gzip_read_open
326             {
327 0     0 1 0 $gzip_read_open;
328             }
329              
330             sub gzip_write_open
331             {
332 0     0 1 0 $gzip_write_open;
333             }
334              
335             sub can_gunzip
336             {
337 0 0   0 0 0 $has_Compress_Zlib || $gzip_external;
338             }
339              
340             sub _import
341             {
342 1     1   1 my $import = shift;
343              
344 1         3 while (@_)
345             {
346 1 50       17 if ($_[0] eq ':gzip_external')
    50          
    50          
347             {
348 0         0 shift;
349              
350 0 0       0 if (@_)
351             {
352 0         0 $gzip_external = shift;
353             }
354             else
355             {
356 0         0 croak "$import: ':gzip_external' requires an argument";
357             }
358             }
359             elsif ($_[0] eq ':gzip_read_open')
360             {
361 0         0 shift;
362              
363 0 0       0 if (@_)
364             {
365 0         0 $gzip_read_open = shift;
366              
367 0 0       0 croak "$import: ':gzip_read_open' '$gzip_read_open' is illegal"
368             unless $gzip_read_open =~ /^.+%s.+\|\s*$/;
369             }
370             else
371             {
372 0         0 croak "$import: ':gzip_read_open' requires an argument";
373             }
374             }
375             elsif ($_[0] eq ':gzip_write_open')
376             {
377 0         0 shift;
378              
379 0 0       0 if (@_)
380             {
381 0         0 $gzip_write_open = shift;
382              
383 0 0       0 croak "$import: ':gzip_write_open' '$gzip_read_open' is illegal"
384             unless $gzip_write_open =~ /^\s*\|.+%s.*$/;
385             }
386             else
387             {
388 0         0 croak "$import: ':gzip_write_open' requires an argument";
389             }
390             }
391             else
392             {
393 1         8 last;
394             }
395             }
396              
397 1         3 return @_;
398             }
399              
400             sub _alias
401             {
402 8     8   20 my $import = shift;
403              
404 8 50 33     70 if ($gzip_external || (!$has_Compress_Zlib && !defined($gzip_external)))
    50 33        
405             {
406 0         0 require IO::Handle;
407              
408 0         0 undef *gzopen;
409 0         0 *gzopen = \&gzopen_external;
410              
411 0         0 *IO::Handle::gzread = \&gzread_external;
412 0         0 *IO::Handle::gzwrite = \&gzwrite_external;
413 0         0 *IO::Handle::gzreadline = \&gzreadline_external;
414 0         0 *IO::Handle::gzeof = \&gzeof_external;
415 0         0 *IO::Handle::gzclose = \&gzclose_external;
416              
417 0         0 $gzip_used = 1;
418             }
419             elsif ($has_Compress_Zlib)
420             {
421 8         27 *gzopen = \&Compress::Zlib::gzopen;
422 8         42 *gzread = \&Compress::Zlib::gzread;
423 8         25 *gzwrite = \&Compress::Zlib::gzwrite;
424 8         18 *gzreadline = \&Compress::Zlib::gzreadline;
425 8         16 *gzeof = \&Compress::Zlib::gzeof;
426             }
427             else
428             {
429 0         0 croak "$import: no Compress::Zlib and no external gzip";
430             }
431              
432 8         10297 $aliased = 1;
433             }
434              
435             sub import
436             {
437 8     8   87 my $class = shift;
438 8         16 my $import = "IO::Zlib::import";
439              
440 8 100       40 if (@_)
441             {
442 1 50       3 if (_import($import, @_))
443             {
444 1         220 croak "$import: '@_' is illegal";
445             }
446             }
447              
448 7         22 _alias($import);
449             }
450              
451             sub TIEHANDLE
452             {
453 17     17   587 my $class = shift;
454 17         37 my @args = @_;
455              
456 17         39 my $self = bless {}, $class;
457              
458 17 100       84 return @args ? $self->OPEN(@args) : $self;
459             }
460              
461             sub DESTROY
462       0     {
463             }
464              
465             sub OPEN
466             {
467 17     17   30 my $self = shift;
468 17         31 my $filename = shift;
469 17         23 my $mode = shift;
470              
471 17 50       44 croak "IO::Zlib::open: needs a filename" unless defined($filename);
472              
473 17         53 $self->{'file'} = gzopen($filename,$mode);
474              
475 17 100       30915 return defined($self->{'file'}) ? $self : undef;
476             }
477              
478             sub CLOSE
479             {
480 12     12   24 my $self = shift;
481              
482 12 50       42 return undef unless defined($self->{'file'});
483              
484 12         40 my $status = $self->{'file'}->gzclose();
485              
486 12         2530 delete $self->{'file'};
487              
488 12 50       721 return ($status == 0) ? 1 : undef;
489             }
490              
491             sub READ
492             {
493 11     11   62 my $self = shift;
494 11         36 my $bufref = \$_[0];
495 11         19 my $nbytes = $_[1];
496 11   100     79 my $offset = $_[2] || 0;
497              
498 11 50       30 croak "IO::Zlib::READ: NBYTES must be specified" unless defined($nbytes);
499              
500 11 100       51 $$bufref = "" unless defined($$bufref);
501              
502 11         53 my $bytesread = $self->{'file'}->gzread(substr($$bufref,$offset),$nbytes);
503              
504 11 50       3351 return undef if $bytesread < 0;
505              
506 11         36 return $bytesread;
507             }
508              
509             sub READLINE
510             {
511 7     7   69 my $self = shift;
512              
513 7         10 my $line;
514              
515 7 100       21 return () if $self->{'file'}->gzreadline($line) <= 0;
516              
517 6 100       876 return $line unless wantarray;
518              
519 1         13 my @lines = $line;
520              
521 1         6 while ($self->{'file'}->gzreadline($line) > 0)
522             {
523 3         389 push @lines, $line;
524             }
525              
526 1         152 return @lines;
527             }
528              
529             sub WRITE
530             {
531 6     6   326 my $self = shift;
532 6         14 my $buf = shift;
533 6         8 my $length = shift;
534 6         10 my $offset = shift;
535              
536 6 50       34 croak "IO::Zlib::WRITE: too long LENGTH" unless $offset + $length <= length($buf);
537              
538 6         48 return $self->{'file'}->gzwrite(substr($buf,$offset,$length));
539             }
540              
541             sub EOF
542             {
543 12     12   23 my $self = shift;
544              
545 12         37 return $self->{'file'}->gzeof();
546             }
547              
548             sub FILENO
549             {
550 0     0   0 return undef;
551             }
552              
553             sub new
554             {
555 15     15 1 5195 my $class = shift;
556 15         42 my @args = @_;
557              
558 15 100       48 _alias("new", @_) unless $aliased; # Some call new IO::Zlib directly...
559              
560 15         72 my $self = gensym();
561              
562 15         219 tie *{$self}, $class, @args;
  15         94  
563              
564 15 100       29 return tied(${$self}) ? bless $self, $class : undef;
  15         120  
565             }
566              
567             sub getline
568             {
569 5     5 1 67 my $self = shift;
570              
571 5         10 return scalar tied(*{$self})->READLINE();
  5         12  
572             }
573              
574             sub getlines
575             {
576 2     2 1 172 my $self = shift;
577              
578 2 100       208 croak "IO::Zlib::getlines: must be called in list context"
579             unless wantarray;
580              
581 1         2 return tied(*{$self})->READLINE();
  1         4  
582             }
583              
584             sub opened
585             {
586 8     8 1 649 my $self = shift;
587              
588 8         11 return defined tied(*{$self})->{'file'};
  8         32  
589             }
590              
591             sub AUTOLOAD
592             {
593 39     39   1390 my $self = shift;
594              
595 39         202 $AUTOLOAD =~ s/.*:://;
596 39         114 $AUTOLOAD =~ tr/a-z/A-Z/;
597              
598 39         52 return tied(*{$self})->$AUTOLOAD(@_);
  39         147  
599             }
600              
601             sub gzopen_external
602             {
603 0     0 1   my $filename = shift;
604 0           my $mode = shift;
605 0           my $fh = IO::Handle->new();
606              
607 0 0         if ($mode =~ /r/)
    0          
608             {
609             # Because someone will try to read ungzipped files
610             # with this we peek and verify the signature. Yes,
611             # this means that we open the file twice (if it is
612             # gzipped).
613             # Plenty of race conditions exist in this code, but
614             # the alternative would be to capture the stderr of
615             # gzip and parse it, which would be a portability nightmare.
616 0 0 0       if (-e $filename && open($fh, $filename))
617             {
618 0           binmode $fh;
619              
620 0           my $sig;
621 0           my $rdb = read($fh, $sig, 2);
622              
623 0 0 0       if ($rdb == 2 && $sig eq "\x1F\x8B")
624             {
625 0           my $ropen = sprintf($gzip_read_open, $filename);
626              
627 0 0         if (open($fh, $ropen))
628             {
629 0           binmode $fh;
630              
631 0           return $fh;
632             }
633             else
634             {
635 0           return undef;
636             }
637             }
638              
639 0 0         seek($fh, 0, SEEK_SET) or
640             die "IO::Zlib: open('$filename', 'r'): seek: $!";
641              
642 0           return $fh;
643             }
644             else
645             {
646 0           return undef;
647             }
648             }
649             elsif ($mode =~ /w/)
650             {
651 0 0         my $level = $mode =~ /([1-9])/ ? "-$1" : "";
652              
653             # To maximize portability we would need to open
654             # two filehandles here, one for "| gzip $level"
655             # and another for "> $filename", and then when
656             # writing copy bytes from the first to the second.
657             # We are using IO::Handle objects for now, however,
658             # and they can only contain one stream at a time.
659 0           my $wopen = sprintf($gzip_write_open, $filename);
660              
661 0 0         if (open($fh, $wopen))
662             {
663 0           $fh->autoflush(1);
664 0           binmode $fh;
665              
666 0           return $fh;
667             }
668             else
669             {
670 0           return undef;
671             }
672             }
673             else
674             {
675 0           croak "IO::Zlib::gzopen_external: mode '$mode' is illegal";
676             }
677              
678 0           return undef;
679             }
680              
681             sub gzread_external
682             {
683 0     0 0   my $file = shift;
684 0           my $bufref = \$_[0];
685 0   0       my $nbytes = $_[1] || 4096;
686              
687             # Use read() instead of sysread() because people may
688             # mix reads and readlines, and we don't want to mess
689             # the stdio buffering. See also gzreadline_external()
690             # and gzwrite_external().
691 0           my $nread = read($file, $$bufref, $nbytes);
692              
693 0 0         return defined $nread ? $nread : -1;
694             }
695              
696             sub gzwrite_external
697             {
698 0     0 0   my $file = shift;
699 0           my $buf = shift;
700              
701             # Using syswrite() is okay (cf. gzread_external())
702             # since the bytes leave this process and buffering
703             # is therefore not an issue.
704 0           my $nwrote = syswrite($file, $buf);
705              
706 0 0         return defined $nwrote ? $nwrote : -1;
707             }
708              
709             sub gzreadline_external
710             {
711 0     0 0   my $file = shift;
712 0           my $bufref = \$_[0];
713              
714             # See the comment in gzread_external().
715 0           $$bufref = readline($file);
716              
717 0 0         return defined $$bufref ? length($$bufref) : -1;
718             }
719              
720             sub gzeof_external
721             {
722 0     0 0   my $file = shift;
723              
724 0           return eof($file);
725             }
726              
727             sub gzclose_external
728             {
729 0     0 0   my $file = shift;
730              
731 0           close($file);
732              
733             # I am not entirely certain why this is needed but it seems
734             # the above close() always fails (as if the stream would have
735             # been already closed - something to do with using external
736             # processes via pipes?)
737 0           return 0;
738             }
739              
740             1;