File Coverage

blib/lib/IO/Zlib.pm
Criterion Covered Total %
statement 164 178 92.1
branch 56 78 71.7
condition 10 19 52.6
subroutine 32 36 88.8
pod 10 16 62.5
total 272 327 83.1


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   520115 use strict;
  9         23  
  9         391  
287 9     9   51 use warnings;
  9         39  
  9         627  
288              
289 9     9   68 use Carp;
  9         18  
  9         1047  
290 9     9   78 use Fcntl qw(SEEK_SET);
  9         36  
  9         629  
291 9     9   6263 use Symbol;
  9         19801  
  9         818  
292 9     9   4566 use Tie::Handle;
  9         24651  
  9         1349  
293              
294             our $VERSION = "1.15";
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         9375  
307 9 50 33     835185 $has_Compress_Zlib = $@ || $Compress::Zlib::VERSION < 2.000 ? 0 : 1;
308             }
309              
310             sub has_Compress_Zlib
311             {
312 1     1 1 337632 $has_Compress_Zlib;
313             }
314              
315             sub gzip_external
316             {
317 3     3 1 31 $gzip_external;
318             }
319              
320             sub gzip_used
321             {
322 1     1 1 8 $gzip_used;
323             }
324              
325             sub gzip_read_open
326             {
327 2     2 1 14 $gzip_read_open;
328             }
329              
330             sub gzip_write_open
331             {
332 2     2 1 18 $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 8     8   15 my $import = shift;
343              
344 8         22 while (@_)
345             {
346 8 100       90 if ($_[0] eq ':gzip_external')
    100          
    100          
347             {
348 3         6 shift;
349              
350 3 100       77 if (@_)
351             {
352 2         9 $gzip_external = shift;
353             }
354             else
355             {
356 1         249 croak "$import: ':gzip_external' requires an argument";
357             }
358             }
359             elsif ($_[0] eq ':gzip_read_open')
360             {
361 2         7 shift;
362              
363 2 50       8 if (@_)
364             {
365 2         6 $gzip_read_open = shift;
366              
367 2 100       433 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 2         4 shift;
378              
379 2 50       10 if (@_)
380             {
381 2         6 $gzip_write_open = shift;
382              
383 2 100       127 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         2 last;
394             }
395             }
396              
397 5         19 return @_;
398             }
399              
400             sub _alias
401             {
402 13     13   29 my $import = shift;
403              
404 13 100 33     103 if ($gzip_external || (!$has_Compress_Zlib && !defined($gzip_external)))
    50 66        
405             {
406 3         34 require IO::Handle;
407              
408 3         17 undef *gzopen;
409 3         10 *gzopen = \&gzopen_external;
410              
411 3         28 *IO::Handle::gzread = \&gzread_external;
412 3         10 *IO::Handle::gzwrite = \&gzwrite_external;
413 3         8 *IO::Handle::gzreadline = \&gzreadline_external;
414 3         10 *IO::Handle::gzeof = \&gzeof_external;
415 3         9 *IO::Handle::gzclose = \&gzclose_external;
416              
417 3         5 $gzip_used = 1;
418             }
419             elsif ($has_Compress_Zlib)
420             {
421 10         44 *gzopen = \&Compress::Zlib::gzopen;
422 10         42 *gzread = \&Compress::Zlib::gzread;
423 10         29 *gzwrite = \&Compress::Zlib::gzwrite;
424 10         24 *gzreadline = \&Compress::Zlib::gzreadline;
425 10         25 *gzeof = \&Compress::Zlib::gzeof;
426             }
427             else
428             {
429 0         0 croak "$import: no Compress::Zlib and no external gzip";
430             }
431              
432 13         14210 $aliased = 1;
433             }
434              
435             sub import
436             {
437 16     16   376 my $class = shift;
438 16         32 my $import = "IO::Zlib::import";
439              
440 16 100       69 if (@_)
441             {
442 8 100       28 if (_import($import, @_))
443             {
444 1         233 croak "$import: '@_' is illegal";
445             }
446             }
447              
448 12         44 _alias($import);
449             }
450              
451             sub TIEHANDLE
452             {
453 22     22   220653 my $class = shift;
454 22         73 my @args = @_;
455              
456 22         138 my $self = bless {}, $class;
457              
458 22 100       157 return @args ? $self->OPEN(@args) : $self;
459             }
460              
461             sub DESTROY
462       0     {
463             }
464              
465             sub OPEN
466             {
467 22     22   48 my $self = shift;
468 22         59 my $filename = shift;
469 22         65 my $mode = shift;
470              
471 22 50       83 croak "IO::Zlib::open: needs a filename" unless defined($filename);
472              
473 22         96 $self->{'file'} = gzopen($filename,$mode);
474              
475 21 100       40042 return defined($self->{'file'}) ? $self : undef;
476             }
477              
478             sub CLOSE
479             {
480 15     15   28 my $self = shift;
481              
482 15 50       66 return undef unless defined($self->{'file'});
483              
484 15         95 my $status = $self->{'file'}->gzclose();
485              
486 15         2781 delete $self->{'file'};
487              
488 15 50       1128 return ($status == 0) ? 1 : undef;
489             }
490              
491             sub READ
492             {
493 13     13   73 my $self = shift;
494 13         33 my $bufref = \$_[0];
495 13         48 my $nbytes = $_[1];
496 13   100     83 my $offset = $_[2] || 0;
497              
498 13 50       53 croak "IO::Zlib::READ: NBYTES must be specified" unless defined($nbytes);
499              
500 13 100       84 $$bufref = "" unless defined($$bufref);
501              
502 13         92 my $bytesread = $self->{'file'}->gzread(substr($$bufref,$offset),$nbytes);
503              
504 13 50       3956 return undef if $bytesread < 0;
505              
506 13         71 return $bytesread;
507             }
508              
509             sub READLINE
510             {
511 7     7   96 my $self = shift;
512              
513 7         10 my $line;
514              
515 7 100       51 return () if $self->{'file'}->gzreadline($line) <= 0;
516              
517 6 100       694 return $line unless wantarray;
518              
519 1         3 my @lines = $line;
520              
521 1         5 while ($self->{'file'}->gzreadline($line) > 0)
522             {
523 3         555 push @lines, $line;
524             }
525              
526 1         198 return @lines;
527             }
528              
529             sub WRITE
530             {
531 7     7   368 my $self = shift;
532 7         15 my $buf = shift;
533 7         18 my $length = shift;
534 7         14 my $offset = shift;
535              
536 7 50       79 croak "IO::Zlib::WRITE: too long LENGTH" unless $offset + $length <= length($buf);
537              
538 7         60 return $self->{'file'}->gzwrite(substr($buf,$offset,$length));
539             }
540              
541             sub EOF
542             {
543 14     14   56 my $self = shift;
544              
545 14         60 return $self->{'file'}->gzeof();
546             }
547              
548             sub FILENO
549             {
550 0     0   0 return undef;
551             }
552              
553             sub new
554             {
555 20     20 1 1172376 my $class = shift;
556 20         94 my @args = @_;
557              
558 20 100       84 _alias("new", @_) unless $aliased; # Some call new IO::Zlib directly...
559              
560 20         90 my $self = gensym();
561              
562 20         4430 tie *{$self}, $class, @args;
  20         309  
563              
564 19 100       65 return tied(${$self}) ? bless $self, $class : undef;
  19         302  
565             }
566              
567             sub getline
568             {
569 5     5 1 40 my $self = shift;
570              
571 5         5 return scalar tied(*{$self})->READLINE();
  5         9  
572             }
573              
574             sub getlines
575             {
576 2     2 1 148 my $self = shift;
577              
578 2 100       247 croak "IO::Zlib::getlines: must be called in list context"
579             unless wantarray;
580              
581 1         2 return tied(*{$self})->READLINE();
  1         6  
582             }
583              
584             sub opened
585             {
586 12     12 1 794 my $self = shift;
587              
588 12         18 return defined tied(*{$self})->{'file'};
  12         78  
589             }
590              
591             sub AUTOLOAD
592             {
593 48     48   1599 my $self = shift;
594              
595 48         408 $AUTOLOAD =~ s/.*:://;
596 48         146 $AUTOLOAD =~ tr/a-z/A-Z/;
597              
598 48         80 return tied(*{$self})->$AUTOLOAD(@_);
  48         317  
599             }
600              
601             sub gzopen_external
602             {
603 5     5 1 8 my $filename = shift;
604 5         7 my $mode = shift;
605 5         56 my $fh = IO::Handle->new();
606              
607 5 100       170 if ($mode =~ /r/)
    100          
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 3 100 66     180 if (-e $filename && open($fh, $filename))
617             {
618 2         11 binmode $fh;
619              
620 2         7 my $sig;
621 2         49 my $rdb = read($fh, $sig, 2);
622              
623 2 50 33     26 if ($rdb == 2 && $sig eq "\x1F\x8B")
624             {
625 2         13 my $ropen = sprintf($gzip_read_open, $filename);
626              
627 2 50       27544 if (open($fh, $ropen))
628             {
629 2         21 binmode $fh;
630              
631 2         75 return $fh;
632             }
633             else
634             {
635 0         0 return undef;
636             }
637             }
638              
639 0 0       0 seek($fh, 0, SEEK_SET) or
640             die "IO::Zlib: open('$filename', 'r'): seek: $!";
641              
642 0         0 return $fh;
643             }
644             else
645             {
646 1         8 return undef;
647             }
648             }
649             elsif ($mode =~ /w/)
650             {
651 1 50       6 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 1         5 my $wopen = sprintf($gzip_write_open, $filename);
660              
661 1 50       17640 if (open($fh, $wopen))
662             {
663 1         37 $fh->autoflush(1);
664 1         7116 binmode $fh;
665              
666 1         83 return $fh;
667             }
668             else
669             {
670 0         0 return undef;
671             }
672             }
673             else
674             {
675 1         164 croak "IO::Zlib::gzopen_external: mode '$mode' is illegal";
676             }
677              
678 0         0 return undef;
679             }
680              
681             sub gzread_external
682             {
683 2     2 0 4 my $file = shift;
684 2         8 my $bufref = \$_[0];
685 2   50     11 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 2         39 my $nread = read($file, $$bufref, $nbytes);
692              
693 2 50       25 return defined $nread ? $nread : -1;
694             }
695              
696             sub gzwrite_external
697             {
698 1     1 0 4 my $file = shift;
699 1         9 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 1         15 my $nwrote = syswrite($file, $buf);
705              
706 1 50       19 return defined $nwrote ? $nwrote : -1;
707             }
708              
709             sub gzreadline_external
710             {
711 0     0 0 0 my $file = shift;
712 0         0 my $bufref = \$_[0];
713              
714             # See the comment in gzread_external().
715 0         0 $$bufref = readline($file);
716              
717 0 0       0 return defined $$bufref ? length($$bufref) : -1;
718             }
719              
720             sub gzeof_external
721             {
722 2     2 0 6 my $file = shift;
723              
724 2         47 return eof($file);
725             }
726              
727             sub gzclose_external
728             {
729 3     3 0 5 my $file = shift;
730              
731 3         3403 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 3         20 return 0;
738             }
739              
740             1;