File Coverage

blib/lib/Archive/Zip/MemberRead.pm
Criterion Covered Total %
statement 83 92 90.2
branch 27 38 71.0
condition 13 24 54.1
subroutine 18 19 94.7
pod 9 12 75.0
total 150 185 81.0


line stmt bran cond sub pod time code
1             package Archive::Zip::MemberRead;
2              
3             =head1 NAME
4              
5             Archive::Zip::MemberRead - A wrapper that lets you read Zip archive members as if they were files.
6              
7             =cut
8              
9             =head1 SYNOPSIS
10              
11             use Archive::Zip;
12             use Archive::Zip::MemberRead;
13             $zip = Archive::Zip->new("file.zip");
14             $fh = Archive::Zip::MemberRead->new($zip, "subdir/abc.txt");
15             while (defined($line = $fh->getline()))
16             {
17             print $fh->input_line_number . "#: $line\n";
18             }
19              
20             $read = $fh->read($buffer, 32*1024);
21             print "Read $read bytes as :$buffer:\n";
22              
23             =head1 DESCRIPTION
24              
25             The Archive::Zip::MemberRead module lets you read Zip archive member data
26             just like you read data from files.
27              
28             =head1 METHODS
29              
30             =over 4
31              
32             =cut
33              
34 3     3   2089 use strict;
  3         5  
  3         87  
35              
36 3     3   15 use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
  3         4  
  3         381  
37              
38 3     3   18 use vars qw{$VERSION};
  3         4  
  3         189  
39              
40             my $nl;
41              
42             BEGIN {
43 3     3   11 $VERSION = '1.66';
44 3         164 $VERSION = eval $VERSION;
45              
46             # Requirement for newline conversion. Should check for e.g., DOS and OS/2 as well, but am too lazy.
47 3 50       2936 $nl = $^O eq 'MSWin32' ? "\r\n" : "\n";
48             }
49              
50             =item Archive::Zip::Member::readFileHandle()
51              
52             You can get a C from an archive member by
53             calling C:
54              
55             my $member = $zip->memberNamed('abc/def.c');
56             my $fh = $member->readFileHandle();
57             while (defined($line = $fh->getline()))
58             {
59             # ...
60             }
61             $fh->close();
62              
63             =cut
64              
65             sub Archive::Zip::Member::readFileHandle {
66 5     5 0 46 return Archive::Zip::MemberRead->new(shift());
67             }
68              
69             =item Archive::Zip::MemberRead->new($zip, $fileName)
70              
71             =item Archive::Zip::MemberRead->new($zip, $member)
72              
73             =item Archive::Zip::MemberRead->new($member)
74              
75             Construct a new Archive::Zip::MemberRead on the specified member.
76              
77             my $fh = Archive::Zip::MemberRead->new($zip, 'fred.c')
78              
79             =cut
80              
81             sub new {
82 9     9 1 275 my ($class, $zip, $file) = @_;
83 9         11 my ($self, $member);
84              
85 9 100 66     65 if ($zip && $file) # zip and filename, or zip and member
    50 33        
      33        
86             {
87 3 100       12 $member = ref($file) ? $file : $zip->memberNamed($file);
88             } elsif ($zip && !$file && ref($zip)) # just member
89             {
90 6         10 $member = $zip;
91             } else {
92 0         0 die(
93             'Archive::Zip::MemberRead::new needs a zip and filename, zip and member, or member'
94             );
95             }
96              
97 9         14 $self = {};
98 9         15 bless($self, $class);
99 9         23 $self->set_member($member);
100 9         65 return $self;
101             }
102              
103             sub set_member {
104 9     9 0 15 my ($self, $member) = @_;
105              
106 9         24 $self->{member} = $member;
107 9         20 $self->set_compression(COMPRESSION_STORED);
108 9         17 $self->rewind();
109             }
110              
111             sub set_compression {
112 9     9 0 14 my ($self, $compression) = @_;
113 9 50       32 $self->{member}->desiredCompressionMethod($compression) if $self->{member};
114             }
115              
116             =item setLineEnd(expr)
117              
118             Set the line end character to use. This is set to \n by default
119             except on Windows systems where it is set to \r\n. You will
120             only need to set this on systems which are not Windows or Unix
121             based and require a line end different from \n.
122             This is a class method so call as C->C
123              
124             =cut
125              
126             sub setLineEnd {
127 0     0 1 0 shift;
128 0         0 $nl = shift;
129             }
130              
131             =item rewind()
132              
133             Rewinds an C so that you can read from it again
134             starting at the beginning.
135              
136             =cut
137              
138             sub rewind {
139 10     10 1 461 my $self = shift;
140              
141 10         28 $self->_reset_vars();
142 10 50       52 $self->{member}->rewindData() if $self->{member};
143             }
144              
145             sub _reset_vars {
146 11     11   14 my $self = shift;
147              
148 11         16 $self->{line_no} = 0;
149 11         18 $self->{at_end} = 0;
150              
151 11         17 delete $self->{buffer};
152             }
153              
154             =item input_record_separator(expr)
155              
156             If the argument is given, input_record_separator for this
157             instance is set to it. The current setting (which may be
158             the global $/) is always returned.
159              
160             =cut
161              
162             sub input_record_separator {
163 2     2 1 501 my $self = shift;
164 2 50       8 if (@_) {
165 2         4 $self->{sep} = shift;
166             $self->{sep_re} =
167 2         4 _sep_as_re($self->{sep}); # Cache the RE as an optimization
168             }
169 2 50       7 return exists $self->{sep} ? $self->{sep} : $/;
170             }
171              
172             # Return the input_record_separator in use as an RE fragment
173             # Note that if we have a per-instance input_record_separator
174             # we can just return the already converted value. Otherwise,
175             # the conversion must be done on $/ every time since we cannot
176             # know whether it has changed or not.
177             sub _sep_re {
178 16     16   24 my $self = shift;
179              
180             # Important to phrase this way: sep's value may be undef.
181 16 100       32 return exists $self->{sep} ? $self->{sep_re} : _sep_as_re($/);
182             }
183              
184             # Convert the input record separator into an RE and return it.
185             sub _sep_as_re {
186 14     14   23 my $sep = shift;
187 14 50       22 if (defined $sep) {
188 14 50       26 if ($sep eq '') {
189 0         0 return "(?:$nl){2,}";
190             } else {
191 14         40 $sep =~ s/\n/$nl/og;
192 14         31 return quotemeta $sep;
193             }
194             } else {
195 0         0 return undef;
196             }
197             }
198              
199             =item input_line_number()
200              
201             Returns the current line number, but only if you're using C.
202             Using C will not update the line number.
203              
204             =cut
205              
206             sub input_line_number {
207 5     5 1 18 my $self = shift;
208 5         9 return $self->{line_no};
209             }
210              
211             =item close()
212              
213             Closes the given file handle.
214              
215             =cut
216              
217             sub close {
218 1     1 1 442 my $self = shift;
219              
220 1         3 $self->_reset_vars();
221 1         3 $self->{member}->endRead();
222             }
223              
224             =item buffer_size([ $size ])
225              
226             Gets or sets the buffer size used for reads.
227             Default is the chunk size used by Archive::Zip.
228              
229             =cut
230              
231             sub buffer_size {
232 16     16 1 21 my ($self, $size) = @_;
233              
234 16 50       28 if (!$size) {
235 16   33     52 return $self->{chunkSize} || Archive::Zip::chunkSize();
236             } else {
237 0         0 $self->{chunkSize} = $size;
238             }
239             }
240              
241             =item getline()
242              
243             Returns the next line from the currently open member.
244             Makes sense only for text files.
245             A read error is considered fatal enough to die.
246             Returns undef on eof. All subsequent calls would return undef,
247             unless a rewind() is called.
248             Note: The line returned has the input_record_separator (default: newline) removed.
249              
250             =item getline( { preserve_line_ending => 1 } )
251              
252             Returns the next line including the line ending.
253              
254             =cut
255              
256             sub getline {
257 16     16 1 2292 my ($self, $argref) = @_;
258              
259 16         31 my $size = $self->buffer_size();
260 16         28 my $sep = $self->_sep_re();
261              
262 16         21 my $preserve_line_ending;
263 16 100       175 if (ref $argref eq 'HASH') {
264 2         3 $preserve_line_ending = $argref->{'preserve_line_ending'};
265 2         9 $sep =~ s/\\([^A-Za-z_0-9])+/$1/g;
266             }
267              
268 16         20 for (; ;) {
269 23 100 66     238 if ( $sep
    100 100        
270             && defined($self->{buffer})
271             && $self->{buffer} =~ s/^(.*?)$sep//s) {
272 14         32 my $line = $1;
273 14         21 $self->{line_no}++;
274 14 100       21 if ($preserve_line_ending) {
275 1         5 return $line . $sep;
276             } else {
277 13         52 return $line;
278             }
279             } elsif ($self->{at_end}) {
280 2 100       5 $self->{line_no}++ if $self->{buffer};
281 2         4 return delete $self->{buffer};
282             }
283 7         21 my ($temp, $status) = $self->{member}->readChunk($size);
284 7 50 66     140 if ($status != AZ_OK && $status != AZ_STREAM_END) {
285 0         0 die "ERROR: Error reading chunk from archive - $status";
286             }
287 7         20 $self->{at_end} = $status == AZ_STREAM_END;
288 7         20 $self->{buffer} .= $$temp;
289             }
290             }
291              
292             =item read($buffer, $num_bytes_to_read)
293              
294             Simulates a normal C system call.
295             Returns the no. of bytes read. C on error, 0 on eof, I:
296              
297             $fh = Archive::Zip::MemberRead->new($zip, "sreeji/secrets.bin");
298             while (1)
299             {
300             $read = $fh->read($buffer, 1024);
301             die "FATAL ERROR reading my secrets !\n" if (!defined($read));
302             last if (!$read);
303             # Do processing.
304             ....
305             }
306              
307             =cut
308              
309             #
310             # All these $_ are required to emulate read().
311             #
312             sub read {
313 1     1 1 5 my $self = $_[0];
314 1         2 my $size = $_[2];
315 1         2 my ($temp, $status, $ret);
316              
317 1         4 ($temp, $status) = $self->{member}->readChunk($size);
318 1 50 33     6 if ($status != AZ_OK && $status != AZ_STREAM_END) {
319 0         0 $_[1] = undef;
320 0         0 $ret = undef;
321             } else {
322 1         2 $_[1] = $$temp;
323 1         2 $ret = length($$temp);
324             }
325 1         2 return $ret;
326             }
327              
328             1;
329              
330             =back
331              
332             =head1 AUTHOR
333              
334             Sreeji K. Das Esreeji_k@yahoo.comE
335              
336             See L by Ned Konz without which this module does not make
337             any sense!
338              
339             Minor mods by Ned Konz.
340              
341             =head1 COPYRIGHT
342              
343             Copyright 2002 Sreeji K. Das.
344              
345             This program is free software; you can redistribute it and/or modify it under
346             the same terms as Perl itself.
347              
348             =cut