Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5767 alewis 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
use strict;
35
 
36
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
37
 
38
use vars qw{$VERSION};
39
 
40
my $nl;
41
 
42
BEGIN {
43
    $VERSION = '1.57';
44
    $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
    $nl = $^O eq 'MSWin32' ? "\r\n" : "\n";
48
}
49
 
50
=item Archive::Zip::Member::readFileHandle()
51
 
52
You can get a C<Archive::Zip::MemberRead> from an archive member by
53
calling C<readFileHandle()>:
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
    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
    my ($class, $zip, $file) = @_;
83
    my ($self, $member);
84
 
85
    if ($zip && $file)    # zip and filename, or zip and member
86
    {
87
        $member = ref($file) ? $file : $zip->memberNamed($file);
88
    } elsif ($zip && !$file && ref($zip))    # just member
89
    {
90
        $member = $zip;
91
    } else {
92
        die(
93
            'Archive::Zip::MemberRead::new needs a zip and filename, zip and member, or member'
94
        );
95
    }
96
 
97
    $self = {};
98
    bless($self, $class);
99
    $self->set_member($member);
100
    return $self;
101
}
102
 
103
sub set_member {
104
    my ($self, $member) = @_;
105
 
106
    $self->{member} = $member;
107
    $self->set_compression(COMPRESSION_STORED);
108
    $self->rewind();
109
}
110
 
111
sub set_compression {
112
    my ($self, $compression) = @_;
113
    $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<Archive::Zip::MemberRead>->C<setLineEnd($nl)>
123
 
124
=cut
125
 
126
sub setLineEnd {
127
    shift;
128
    $nl = shift;
129
}
130
 
131
=item rewind()
132
 
133
Rewinds an C<Archive::Zip::MemberRead> so that you can read from it again
134
starting at the beginning.
135
 
136
=cut
137
 
138
sub rewind {
139
    my $self = shift;
140
 
141
    $self->_reset_vars();
142
    $self->{member}->rewindData() if $self->{member};
143
}
144
 
145
sub _reset_vars {
146
    my $self = shift;
147
 
148
    $self->{line_no} = 0;
149
    $self->{at_end}  = 0;
150
 
151
    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
    my $self = shift;
164
    if (@_) {
165
        $self->{sep} = shift;
166
        $self->{sep_re} =
167
          _sep_as_re($self->{sep});    # Cache the RE as an optimization
168
    }
169
    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
    my $self = shift;
179
 
180
    # Important to phrase this way: sep's value may be undef.
181
    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
    my $sep = shift;
187
    if (defined $sep) {
188
        if ($sep eq '') {
189
            return "(?:$nl){2,}";
190
        } else {
191
            $sep =~ s/\n/$nl/og;
192
            return quotemeta $sep;
193
        }
194
    } else {
195
        return undef;
196
    }
197
}
198
 
199
=item input_line_number()
200
 
201
Returns the current line number, but only if you're using C<getline()>.
202
Using C<read()> will not update the line number.
203
 
204
=cut
205
 
206
sub input_line_number {
207
    my $self = shift;
208
    return $self->{line_no};
209
}
210
 
211
=item close()
212
 
213
Closes the given file handle.
214
 
215
=cut
216
 
217
sub close {
218
    my $self = shift;
219
 
220
    $self->_reset_vars();
221
    $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
    my ($self, $size) = @_;
233
 
234
    if (!$size) {
235
        return $self->{chunkSize} || Archive::Zip::chunkSize();
236
    } else {
237
        $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
    my ($self, $argref) = @_;
258
 
259
    my $size = $self->buffer_size();
260
    my $sep  = $self->_sep_re();
261
 
262
    my $preserve_line_ending;
263
    if (ref $argref eq 'HASH') {
264
        $preserve_line_ending = $argref->{'preserve_line_ending'};
265
        $sep =~ s/\\([^A-Za-z_0-9])+/$1/g;
266
    }
267
 
268
    for (; ;) {
269
        if (   $sep
270
            && defined($self->{buffer})
271
            && $self->{buffer} =~ s/^(.*?)$sep//s) {
272
            my $line = $1;
273
            $self->{line_no}++;
274
            if ($preserve_line_ending) {
275
                return $line . $sep;
276
            } else {
277
                return $line;
278
            }
279
        } elsif ($self->{at_end}) {
280
            $self->{line_no}++ if $self->{buffer};
281
            return delete $self->{buffer};
282
        }
283
        my ($temp, $status) = $self->{member}->readChunk($size);
284
        if ($status != AZ_OK && $status != AZ_STREAM_END) {
285
            die "ERROR: Error reading chunk from archive - $status";
286
        }
287
        $self->{at_end} = $status == AZ_STREAM_END;
288
        $self->{buffer} .= $$temp;
289
    }
290
}
291
 
292
=item read($buffer, $num_bytes_to_read)
293
 
294
Simulates a normal C<read()> system call.
295
Returns the no. of bytes read. C<undef> on error, 0 on eof, I<e.g.>:
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
    my $self = $_[0];
314
    my $size = $_[2];
315
    my ($temp, $status, $ret);
316
 
317
    ($temp, $status) = $self->{member}->readChunk($size);
318
    if ($status != AZ_OK && $status != AZ_STREAM_END) {
319
        $_[1] = undef;
320
        $ret = undef;
321
    } else {
322
        $_[1] = $$temp;
323
        $ret = length($$temp);
324
    }
325
    return $ret;
326
}
327
 
328
1;
329
 
330
=back
331
 
332
=head1 AUTHOR
333
 
334
Sreeji K. Das E<lt>sreeji_k@yahoo.comE<gt>
335
 
336
See L<Archive::Zip> 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