use warnings;
use bytes;
-use IO::Uncompress::RawInflate 2.020 ;
-use IO::Compress::Base::Common 2.020 qw(:Status createSelfTiedObject);
-use IO::Uncompress::Adapter::Inflate 2.020 ;
-use IO::Uncompress::Adapter::Identity 2.020 ;
-use IO::Compress::Zlib::Extra 2.020 ;
-use IO::Compress::Zip::Constants 2.020 ;
+use IO::Uncompress::RawInflate 2.021 ;
+use IO::Compress::Base::Common 2.021 qw(:Status createSelfTiedObject);
+use IO::Uncompress::Adapter::Inflate 2.021 ;
+use IO::Uncompress::Adapter::Identity 2.021 ;
+use IO::Compress::Zlib::Extra 2.021 ;
+use IO::Compress::Zip::Constants 2.021 ;
-use Compress::Raw::Zlib 2.020 qw(crc32) ;
+use Compress::Raw::Zlib 2.021 qw(crc32) ;
BEGIN
{
eval { require IO::Uncompress::Adapter::Bunzip2 ;
import IO::Uncompress::Adapter::Bunzip2 } ;
- #eval { require IO::Uncompress::Adapter::UnLzma ;
- # import IO::Uncompress::Adapter::UnLzma } ;
+ eval { require IO::Uncompress::Adapter::UnLzma ;
+ import IO::Uncompress::Adapter::UnLzma } ;
}
our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $UnzipError, %headerLookup);
-$VERSION = '2.020';
+$VERSION = '2.021';
$UnzipError = '';
@ISA = qw(Exporter IO::Uncompress::RawInflate);
sub getExtraParams
{
- use IO::Compress::Base::Common 2.020 qw(:Parse);
+ use IO::Compress::Base::Common 2.021 qw(:Parse);
return (
# # Zip header fields
- 'Name' => [1, 1, Parse_any, undef],
+ 'Name' => [1, 1, Parse_any, undef],
-# 'Streaming' => [1, 1, Parse_boolean, 1],
+# 'Stream' => [1, 1, Parse_boolean, 1],
+ # This means reading the central directory to get
+ # 1. the local header offsets
+ # 2. The compressed data length
);
}
}
+sub fastForward
+{
+ my $self = shift;
+ my $offset = shift;
+
+ # TODO - if Stream isn't enabled & reading from file, use seek
+
+ my $buffer = '';
+ my $c = 1024 * 16;
+
+ while ($offset > 0)
+ {
+ $c = length $offset
+ if length $offset < $c ;
+
+ $offset -= $c;
+
+ $self->smartReadExact(\$buffer, $c)
+ or return 0;
+ }
+
+ return 1;
+}
+
sub readHeader
{
}
# skip the data
+ # TODO - when Stream is off, use seek
my $buffer;
if (*$self->{ZipData}{Streaming}) {
or return $self->saveErrorString(undef, "Truncated file");
}
else {
- my $c = $hdr->{CompressedLength}->get32bit();
- $self->smartReadExact(\$buffer, $c)
+ my $c = $hdr->{CompressedLength}->get64bit();
+ $self->fastForward($c)
or return $self->saveErrorString(undef, "Truncated file");
$buffer = '';
}
*$self->{ZipData}{UnCompressedLen});
}
+ *$self->{Info}{CRC32} = *$self->{ZipData}{CRC32} ;
+ *$self->{Info}{CompressedLength} = $cSize->get64bit();
+ *$self->{Info}{UncompressedLength} = $uSize->get64bit();
+
if (*$self->{Strict}) {
return $self->TrailerError("CRC mismatch")
if $CRC32 != *$self->{ZipData}{CRC32} ;
my $keep = $magic . $buffer ;
my ($sizeLo, $sizeHi) = unpack ("V V", $buffer);
+ my $size = $sizeHi * 0xFFFFFFFF + $sizeLo;
- # TODO - take SizeHi into account
- $self->smartReadExact(\$buffer, $sizeLo)
+ $self->fastForward($size)
or return $self->TrailerError("Minimum header size is " .
- $sizeLo . " bytes") ;
+ $size . " bytes") ;
- $keep .= $buffer ;
- *$self->{HeaderPending} = $keep ;
+ #$keep .= $buffer ;
+ #*$self->{HeaderPending} = $keep ;
#my $versionMadeBy = unpack ("v", substr($buffer, 0, 2));
#my $extractVersion = unpack ("v", substr($buffer, 2, 2));
my $compressedMethod = unpack ("v", substr($buffer, 8-4, 2));
my $lastModTime = unpack ("V", substr($buffer, 10-4, 4));
my $crc32 = unpack ("V", substr($buffer, 14-4, 4));
- my $compressedLength = new U64 unpack ("V", substr($buffer, 18-4, 4));
- my $uncompressedLength = new U64 unpack ("V", substr($buffer, 22-4, 4));
+ my $compressedLength = U64::newUnpack_V32 substr($buffer, 18-4, 4);
+ my $uncompressedLength = U64::newUnpack_V32 substr($buffer, 22-4, 4);
my $filename_length = unpack ("v", substr($buffer, 26-4, 2));
my $extra_length = unpack ("v", substr($buffer, 28-4, 2));
my $buff = ${ $Extra{ZIP_EXTRA_ID_ZIP64()} };
- # TODO - This code assumes that all the fields in the Zip64
+ # This code assumes that all the fields in the Zip64
# extra field aren't necessarily present. The spec says that
# they only exist if the equivalent local headers are -1.
- # Need to check that info-zip fills out -1 in the local header
- # correctly.
if (! $streamingMode) {
my $offset = 0 ;
- $uncompressedLength = U64::newUnpack_V64 substr($buff, 0, 8)
- if $uncompressedLength == 0xFFFF ;
+ if ($uncompressedLength->get32bit() == 0xFFFFFFFF ) {
+ $uncompressedLength
+ = U64::newUnpack_V64 substr($buff, 0, 8);
- $offset += 8 ;
+ $offset += 8 ;
+ }
- $compressedLength = U64::newUnpack_V64 substr($buff, $offset, 8)
- if $compressedLength == 0xFFFF ;
+ if ($compressedLength->get32bit() == 0xFFFFFFFF) {
- $offset += 8 ;
+ $compressedLength
+ = U64::newUnpack_V64 substr($buff, $offset, 8);
- #my $cheaderOffset = U64::newUnpack_V64 substr($buff, 16, 8);
- #my $diskNumber = unpack ("V", substr($buff, 24, 4));
+ $offset += 8 ;
+ }
}
}
}
*$self->{ZipData}{CompressedLen} = $compressedLength;
*$self->{ZipData}{UnCompressedLen} = $uncompressedLength;
*$self->{CompressedInputLengthRemaining} =
- *$self->{CompressedInputLength} = $compressedLength->get32bit();
+ *$self->{CompressedInputLength} = $compressedLength->get64bit();
}
+ *$self->{ZipData}{CRC32} = crc32(undef);
*$self->{ZipData}{Method} = $compressedMethod;
if ($compressedMethod == ZIP_CM_DEFLATE)
{
my $obj = IO::Uncompress::Adapter::Inflate::mkUncompObject(1,0,0);
*$self->{Uncomp} = $obj;
- *$self->{ZipData}{CRC32} = crc32(undef);
}
elsif ($compressedMethod == ZIP_CM_BZIP2)
{
my $obj = IO::Uncompress::Adapter::Bunzip2::mkUncompObject();
*$self->{Uncomp} = $obj;
- *$self->{ZipData}{CRC32} = crc32(undef);
}
-# elsif ($compressedMethod == ZIP_CM_LZMA)
-# {
-# return $self->HeaderError("Unsupported Compression format $compressedMethod")
-# if ! defined $IO::Uncompress::Adapter::UnLzma::VERSION ;
-#
-# *$self->{Type} = 'zip-lzma';
-#
-# my $obj = IO::Uncompress::Adapter::UnLzma::mkUncompObject();
-#
-# *$self->{Uncomp} = $obj;
-# *$self->{ZipData}{CRC32} = crc32(undef);
-# }
+ elsif ($compressedMethod == ZIP_CM_LZMA)
+ {
+ return $self->HeaderError("Unsupported Compression format $compressedMethod")
+ if ! defined $IO::Uncompress::Adapter::UnLzma::VERSION ;
+
+ *$self->{Type} = 'zip-lzma';
+ my $LzmaHeader;
+ $self->smartReadExact(\$LzmaHeader, 4)
+ or return $self->saveErrorString(undef, "Truncated file");
+ my ($verHi, $verLo) = unpack ("CC", substr($LzmaHeader, 0, 2));
+ my $LzmaPropertiesSize = unpack ("v", substr($LzmaHeader, 2, 2));
+
+
+ my $LzmaPropertyData;
+ $self->smartReadExact(\$LzmaPropertyData, $LzmaPropertiesSize)
+ or return $self->saveErrorString(undef, "Truncated file");
+ #my $LzmaInfo = unpack ("C", substr($LzmaPropertyData, 0, 1));
+ #my $LzmaDictSize = unpack ("V", substr($LzmaPropertyData, 1, 4));
+
+ # Create an LZMA_Alone header
+ $self->pushBack($LzmaPropertyData .
+ $uncompressedLength->getPacked_V64());
+
+ my $obj =
+ IO::Uncompress::Adapter::UnLzma::mkUncompObject();
+
+ *$self->{Uncomp} = $obj;
+ }
elsif ($compressedMethod == ZIP_CM_STORE)
{
# TODO -- add support for reading uncompressed
? "Deflated"
: $compressedMethod == ZIP_CM_BZIP2
? "Bzip2"
- : $compressedMethod == ZIP_CM_STORE
- ? "Stored"
- : "Unknown" ,
+ : $compressedMethod == ZIP_CM_LZMA
+ ? "Lzma"
+ : $compressedMethod == ZIP_CM_STORE
+ ? "Stored"
+ : "Unknown" ,
# 'TextFlag' => $flag & GZIP_FLG_FTEXT ? 1 : 0,
# 'HeaderCRCFlag' => $flag & GZIP_FLG_FHCRC ? 1 : 0,
{
my $self = shift ;
- if (*$self->{ZipData}{Method} == 12) {
- *$self->{ZipData}{CRC32} = crc32(${$_[0]}, *$self->{ZipData}{CRC32});
+ if (*$self->{ZipData}{Method} == ZIP_CM_DEFLATE) {
+ *$self->{ZipData}{CRC32} = *$self->{Uncomp}->crc32() ;
}
else {
- *$self->{ZipData}{CRC32} = *$self->{Uncomp}->crc32() ;
+ *$self->{ZipData}{CRC32} = crc32(${$_[0]}, *$self->{ZipData}{CRC32});
}
}
=head2 Examples
To read the contents of the file C<file1.txt.zip> and write the
-compressed data to the file C<file1.txt>.
+uncompressed data to the file C<file1.txt>.
use strict ;
use warnings ;