| 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 |
||||||
| 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 |
||||||
| 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 |
||||||
| 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 |
||||||
| 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 |
||||||
| 295 | Returns the no. of bytes read. C |
||||||
| 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 E |
||||||
| 335 | |||||||
| 336 | See L |
||||||
| 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 |