This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Update IO-Compress to CPAN version 2.096
authorTodd Rinaldo <toddr@cpan.org>
Tue, 15 Sep 2020 14:43:03 +0000 (09:43 -0500)
committerℕicolas ℝ <nicolas@atoomic.org>
Tue, 15 Sep 2020 16:14:31 +0000 (10:14 -0600)
[DELTA]

2.096 31 July 2020

* Add Zip support for Zstd
508258baeeec51ba49c3c07d2dda7c19e3194985

* Add support for Zip/Unzip with XZ compression
6d240d3b3514d627a751ec82fe71f2e236301e19
3c0046e8bc65ef467b9153722609654d3ccc5bbd

2.095 19 July 2020

* Add Support for Zstandard in AnyUncompress

2.094 13 July 2020

* bin/zipdetails version 2

7acb49ff4ca67051deaffd7f988556dae0dd884b small update
f5988eebc21a4d0b96e0b094e6e9bf8d3dcb1763 Better error messages for missing Zip64 records
d224dcc321dd1ff120345ac3a19286ecdc79776f Add note about warning output
4caa0e5117c4c214f457d90f9a87d00772a79622 Add --version option
6c045c859d2b6bab0398833f207d7f9b803bbbab Version 2
df97743ffa1da816936e8ef504c9d561d66bb0ed Beef up some error cases
073129c4f44ebd3cc2c5381ffa824fc09b474c29 Rename a couple of unused signatures
72568c7d9edfd3e2fb6647dce6ea511e9caa186c update comment
1088199809cabb9c565ac23f065988683aacd323 Merge branch 'master' of https://github.com/pmqs/IO-Compress
ad987ab95e3f3fa02fcf526736ad2da78d327460 Merge pull request #10 from fabiensanglard/master
ac76d1b3d3f23077b1700778226edd68c50d81a8 fix typo
5950d7e724479f0eceffe68ae515ac117ff6a5ef Don't output "Extra Payload" if length is zero
dbd3160decd9b761dbad7aaae2ec46c0173125ef Merge pull request #12 from fabiensanglard/extra
7ae4a98124c9195ca5286e3ac7d2cbe37fa2b644 Recover from bad extra subfield
3e12e62916da31c003a7273293bc32bb9a31f85f Fix typo
f3a0a4717433d32743f17d40adc30e11bea60868 Fix wrong START offset
6f078dca715473276556afb0b8582bb69efa7230 Typo for Implode string "Shannon-Fano Trees"
4e25fed1a8e29518fa38f0610a5ca33ca41e9d89 some small documentation updates.
1be04bf4bd5fb023ad276ecabdbc170823bac465 Add decoder for 'Open Packaging Growth Hint'
2da58735bdbd1149863014dd08a7cea0334f52d5 update compression method 16
82a9612676ae192747b8bcbf586b09408c3b72ce Add extra fields 0x20-0x23 from APPNOTE 6.3.5
bc5e2ffbc560b236bc3be0f977ce744f2a2afbfb remove trailing whitespace
3f70119190671b00eb432e36904aa9dbb2fb8f69 minor documentation changes

35 files changed:
MANIFEST
Porting/Maintainers.pl
cpan/IO-Compress/Makefile.PL
cpan/IO-Compress/bin/streamzip
cpan/IO-Compress/bin/zipdetails
cpan/IO-Compress/lib/Compress/Zlib.pm
cpan/IO-Compress/lib/IO/Compress/Adapter/Bzip2.pm
cpan/IO-Compress/lib/IO/Compress/Adapter/Deflate.pm
cpan/IO-Compress/lib/IO/Compress/Adapter/Identity.pm
cpan/IO-Compress/lib/IO/Compress/Base.pm
cpan/IO-Compress/lib/IO/Compress/Base/Common.pm
cpan/IO-Compress/lib/IO/Compress/Bzip2.pm
cpan/IO-Compress/lib/IO/Compress/Deflate.pm
cpan/IO-Compress/lib/IO/Compress/FAQ.pod
cpan/IO-Compress/lib/IO/Compress/Gzip.pm
cpan/IO-Compress/lib/IO/Compress/Gzip/Constants.pm
cpan/IO-Compress/lib/IO/Compress/RawDeflate.pm
cpan/IO-Compress/lib/IO/Compress/Zip.pm
cpan/IO-Compress/lib/IO/Compress/Zip/Constants.pm
cpan/IO-Compress/lib/IO/Compress/Zlib/Constants.pm
cpan/IO-Compress/lib/IO/Compress/Zlib/Extra.pm
cpan/IO-Compress/lib/IO/Uncompress/Adapter/Bunzip2.pm
cpan/IO-Compress/lib/IO/Uncompress/Adapter/Identity.pm
cpan/IO-Compress/lib/IO/Uncompress/Adapter/Inflate.pm
cpan/IO-Compress/lib/IO/Uncompress/AnyInflate.pm
cpan/IO-Compress/lib/IO/Uncompress/AnyUncompress.pm
cpan/IO-Compress/lib/IO/Uncompress/Base.pm
cpan/IO-Compress/lib/IO/Uncompress/Bunzip2.pm
cpan/IO-Compress/lib/IO/Uncompress/Gunzip.pm
cpan/IO-Compress/lib/IO/Uncompress/Inflate.pm
cpan/IO-Compress/lib/IO/Uncompress/RawInflate.pm
cpan/IO-Compress/lib/IO/Uncompress/Unzip.pm
cpan/IO-Compress/t/000prereq.t
cpan/IO-Compress/t/105oneshot-zip-only.t
cpan/IO-Compress/t/files/testfile1.odt [new file with mode: 0644]

index 4b30f2c..e8161a9 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1148,6 +1148,7 @@ cpan/IO-Compress/t/files/encrypt-standard.zip
 cpan/IO-Compress/t/files/jar.zip
 cpan/IO-Compress/t/files/meta.xml
 cpan/IO-Compress/t/files/test.ods
+cpan/IO-Compress/t/files/testfile1.odt
 cpan/IO-Compress/t/globmapper.t                                IO::Compress
 cpan/IO-Socket-IP/lib/IO/Socket/IP.pm                  IO::Socket::IP
 cpan/IO-Socket-IP/t/00use.t                            IO::Socket::IP tests
index 94f3653..16a3541 100755 (executable)
@@ -643,7 +643,7 @@ use File::Glob qw(:case);
     },
 
     'IO-Compress' => {
-        'DISTRIBUTION' => 'PMQS/IO-Compress-2.093.tar.gz',
+        'DISTRIBUTION' => 'PMQS/IO-Compress-2.096.tar.gz',
         'FILES'        => q[cpan/IO-Compress],
         'EXCLUDED'     => [
             qr{^examples/},
index d22a4c2..1249a3c 100644 (file)
@@ -3,7 +3,7 @@
 use strict ;
 require 5.006 ;
 
-$::VERSION = '2.093' ;
+$::VERSION = '2.096' ;
 
 use lib '.';
 use private::MakeUtil;
@@ -12,10 +12,10 @@ use ExtUtils::MakeMaker 5.16 ;
 UpDowngrade(getPerlFiles('MANIFEST'))
     unless $ENV{PERL_CORE};
 
-WriteMakefile( 
+WriteMakefile(
     NAME         => 'IO::Compress',
     VERSION_FROM => 'lib/IO/Compress/Base.pm',
-    'dist'       => { COMPRESS     => 'gzip', 
+    'dist'       => { COMPRESS     => 'gzip',
                       TARFLAGS     => '-chvf',
                       SUFFIX       => 'gz',
                       DIST_DEFAULT => 'MyTrebleCheck tardist',
@@ -25,14 +25,15 @@ WriteMakefile(
       $ENV{SKIP_FOR_CORE}
         ? ()
            : (PREREQ_PM   => { 'Compress::Raw::Bzip2' => $::VERSION,
-                                   'Compress::Raw::Zlib'   => $::VERSION,
+                                   'Compress::Raw::Zlib'  => $::VERSION,
                                    'Scalar::Util'  => 0,
-                                   $] >= 5.005 && $] < 5.006   
-                                ? ('File::BSDGlob' => 0) 
+                            'Encode'        => 0,
+                                   $] >= 5.005 && $] < 5.006
+                                ? ('File::BSDGlob' => 0)
                                 : () }
              )
     ),
-       
+
     (
     $] >= 5.005
         ? (ABSTRACT => 'IO Interface to compressed data files/buffers',
@@ -43,16 +44,16 @@ WriteMakefile(
     INSTALLDIRS => ($] >= 5.009 && $] < 5.011 ? 'perl' : 'site'),
 
     EXE_FILES => ['bin/zipdetails', 'bin/streamzip'],
-    
+
     (
     $] >= 5.009 && $] <= 5.011001 && ! $ENV{PERL_CORE}
         ? (INSTALLPRIVLIB    => '$(INSTALLARCHLIB)')
         : ()
     ),
 
-     ( eval { ExtUtils::MakeMaker->VERSION(6.46) }  
+     ( eval { ExtUtils::MakeMaker->VERSION(6.46) }
         ? ( META_MERGE  => {
-    
+
                 "meta-spec" => { version => 2 },
 
                 no_index => {
@@ -60,7 +61,7 @@ WriteMakefile(
                 },
 
                 resources   => {
-                
+
                     bugtracker  => {
                         web     => 'https://github.com/pmqs/IO-Compress/issues'
                     },
@@ -71,17 +72,16 @@ WriteMakefile(
                         type    => 'git',
                         url     => 'git://github.com/pmqs/IO-Compress.git',
                         web     => 'https://github.com/pmqs/IO-Compress',
-                    },        
+                    },
                 },
-              } 
-            ) 
+              }
+            )
         : ()
     ),
 
     ((ExtUtils::MakeMaker->VERSION() gt '6.30') ?
-        ('LICENSE'  => 'perl')         : ()),    
+        ('LICENSE'  => 'perl')         : ()),
 
 ) ;
 
 # end of file Makefile.PL
-
index 1a34fef..02b6c2c 100644 (file)
@@ -12,7 +12,7 @@ use IO::Compress::Zip qw(zip
                          ZIP_CM_LZMA );
 use Getopt::Long;
 
-my $VERSION = '1.0';
+my $VERSION = '1.001';
 
 my $compression_method = ZIP_CM_DEFLATE;
 my $stream = 0;
@@ -63,7 +63,7 @@ sub lookupMethod
     if ($method == ZIP_CM_LZMA)
     {
         eval ' use IO::Compress::Adapter::Lzma';
-        die "Method =. LZMA needs IO::Compress::Adapter::Lzma\n"
+        die "Method 'LZMA' needs IO::Compress::Adapter::Lzma\n"
             if ! defined $IO::Compress::Lzma::VERSION;
     }
 
@@ -72,21 +72,24 @@ sub lookupMethod
 
 sub Usage
 {
-    die <<EOM;
-streamzip [OPTIONS]
+    print <<EOM;
+Usage:
+  producer | streamzip [OPTIONS] | consumer
+  producer | streamzip [OPTIONS] -zipfile=output.zip
 
 Stream data from stdin, compress into a Zip container, and stream to stdout.
 
 OPTIONS
 
-  -zipfile=F      Write zip container to the filename F
-  -member-name=M  member name [Default '-']
+  -zipfile=F      Write zip container to the filename 'F'
+                  Outputs to stdout if zipfile not specified.
+  -member-name=M  Set member name to 'M' [Default '-']
   -zip64          Create a Zip64-compliant zip file [Default: No]
-                  Use Zip64 if input is greater than 4Gig.
-  -stream         Write a streamed zip file
+                  Enable Zip64 if input is greater than 4Gig.
+  -stream         Force a streamed zip file when zipfile is also enabled.
                   Only applies when 'zipfile' option is used. [Default: No]
-                  Always enabled when writing to stdout.
-  -method=M       Compress using method "M".
+                  Stream is always enabled when writing to stdout.
+  -method=M       Compress using method 'M'.
                   Valid methods are
                     store    Store without compression
                     deflate  Use Deflate compression [Deflault]
@@ -95,12 +98,13 @@ OPTIONS
                   Lzma needs IO::Compress::Lzma to be installed.
   -version        Display version number [$VERSION]
 
-Copyright (c) 2019 Paul Marquess. All rights reserved.
+Copyright (c) 2019-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 EOM
+    exit;
 }
 
 
@@ -116,13 +120,15 @@ streamzip - create a zip file from stdin
 
 =head1 DESCRIPTION
 
-This program will read data from stdin, compress it into a zip container and,
-by default, write a I<streamed> zip file to stdout. No temporary files are created.
+This program will read data from C<stdin>, compress it into a zip container
+and, by default, write a I<streamed> zip file to C<stdout>. No temporary
+files are created.
 
-The zip container written to stdout is, by necessity, written in streaming
-format.  Most programs that read Zip files can cope with a streamed zip file,
-but if interoperability is important, and your workflow allows you to write the 
-zip file directly to disk you can create a non-streamed zip file using the C<zipfile> option.
+The zip container written to C<stdout> is, by necessity, written in
+streaming format. Most programs that read Zip files can cope with a
+streamed zip file, but if interoperability is important, and your workflow
+allows you to write the zip file directly to disk you can create a
+non-streamed zip file using the C<zipfile> option.
 
 =head2 OPTIONS
 
@@ -130,48 +136,48 @@ zip file directly to disk you can create a non-streamed zip file using the C<zip
 
 =item -zip64
 
-Create a Zip64-compliant zip container.
-Use this option if the input is greater than 4Gig.
+Create a Zip64-compliant zip container. Use this option if the input is
+greater than 4Gig.
 
 Default is disabled.
 
-=item  -zipfile=F     
+=item  -zipfile=F
 
-Write zip container to the filename F.
+Write zip container to the filename C<F>.
 
-Use the C<Stream> option to enable the creation of a  streamed zip file.
+Use the C<Stream> option to force the creation of a streamed zip file.
 
-=item  -member-name=M  
+=item  -member-name=M
 
 This option is used to name the "file" in the zip container.
 
 Default is '-'.
 
-=item  -stream         
+=item  -stream
 
-Ignored when writing to stdout.
+Ignored when writing to C<stdout>.
 
-If the C<zipfile> option is specified, including this option
-will trigger the creation of a streamed zip file.
+If the C<zipfile> option is specified, including this option will trigger
+the creation of a streamed zip file.
 
-Default: Always enabled when writing to stdout, otherwise disabled.
+Default: Always enabled when writing to C<stdout>, otherwise disabled.
 
-=item  -method=M       
+=item  -method=M
 
-Compress using method "M".
+Compress using method C<M>.
 
 Valid method names are
 
     * store    Store without compression
     * deflate  Use Deflate compression [Deflault]
     * bzip2    Use Bzip2 compression
-    * lzma     Use LZMA compression 
+    * lzma     Use LZMA compression
 
-Note that Lzma compress needs IO::Compress::Lzma to be installed.
+Note that Lzma compress needs C<IO::Compress::Lzma> to be installed.
 
-Default is deflate.
+Default is C<deflate>.
 
-=item  -version        
+=item  -version
 
 Display version number [$VERSION]
 
@@ -183,12 +189,12 @@ Display help
 
 =head2 When to use a Streamed Zip File
 
-A Zip file created with streaming mode enabled allows you to create a zip file 
-in situations where you cannot seek backwards/forwards in the file. 
+A Streamed Zip File is useful in situations where you cannot seek
+backwards/forwards in the file.
 
-A good examples is when you are
-serving dynamic content from a Web Server straight into a socket 
-without needing to create a temporary zip file in the filesystsm.
+A good examples is when you are serving dynamic content from a Web Server
+straight into a socket without needing to create a temporary zip file in
+the filesystsm.
 
 Similarly if your workfow uses a Linux pipelined commands.
 
@@ -203,10 +209,9 @@ L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
 Paul Marquess F<pmqs@cpan.org>.
 
-=head1 COPYRIGHT 
+=head1 COPYRIGHT
 
-Copyright (c) 2019 Paul Marquess. All rights reserved.
+Copyright (c) 2019-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or modify it
-under the same terms as Perl itself. 
-
+under the same terms as Perl itself.
index bff32a1..6a054cd 100644 (file)
@@ -11,14 +11,15 @@ use warnings ;
 
 use IO::File;
 use Encode;
+use Getopt::Long;
 
-# Compression types 
+# Compression types
 use constant ZIP_CM_STORE                      => 0 ;
 use constant ZIP_CM_IMPLODE                    => 6 ;
 use constant ZIP_CM_DEFLATE                    => 8 ;
 use constant ZIP_CM_BZIP2                      => 12 ;
 use constant ZIP_CM_LZMA                       => 14 ;
-use constant ZIP_CM_PPMD                       => 98 ; 
+use constant ZIP_CM_PPMD                       => 98 ;
 
 # General Purpose Flag
 use constant ZIP_GP_FLAG_ENCRYPTED_MASK        => (1 << 0) ;
@@ -38,8 +39,8 @@ use constant ZIP_CENTRAL_HDR_SIG               => 0x02014b50;
 use constant ZIP_END_CENTRAL_HDR_SIG           => 0x06054b50;
 use constant ZIP64_END_CENTRAL_REC_HDR_SIG     => 0x06064b50;
 use constant ZIP64_END_CENTRAL_LOC_HDR_SIG     => 0x07064b50;
-use constant ZIP64_ARCHIVE_EXTRA_SIG           => 0x08064b50;
-use constant ZIP64_DIGITAL_SIGNATURE_SIG       => 0x05054b50;
+use constant ZIP_ARCHIVE_EXTRA_DATA_SIG        => 0x08064b50;
+use constant ZIP_DIGITAL_SIGNATURE_SIG         => 0x05054b50;
 
 use constant ZIP_ARCHIVE_EXTRA_DATA_RECORD_SIG => 0x08064b50;
 
@@ -50,7 +51,7 @@ use constant ZIP_EXTRA_SUBFIELD_ID_SIZE     => 2 ;
 use constant ZIP_EXTRA_SUBFIELD_LEN_SIZE    => 2 ;
 use constant ZIP_EXTRA_SUBFIELD_HEADER_SIZE => ZIP_EXTRA_SUBFIELD_ID_SIZE +
                                                ZIP_EXTRA_SUBFIELD_LEN_SIZE;
-use constant ZIP_EXTRA_SUBFIELD_MAX_SIZE    => ZIP_EXTRA_MAX_SIZE - 
+use constant ZIP_EXTRA_SUBFIELD_MAX_SIZE    => ZIP_EXTRA_MAX_SIZE -
                                                ZIP_EXTRA_SUBFIELD_HEADER_SIZE;
 
 my %ZIP_CompressionMethods =
@@ -71,11 +72,13 @@ my %ZIP_CompressionMethods =
          13 => 'Reserved by PKWARE',
          14 => 'LZMA',
          15 => 'Reserved by PKWARE',
-         16 => 'Reserved by PKWARE',
+         16 => 'IBM z/OS CMPSC Compression',
          17 => 'Reserved by PKWARE',
          18 => 'File is compressed using IBM TERSE (new)',
          19 => 'IBM LZ77 z Architecture (PFS)',
-         95 => 'XZ',         
+         93 => 'Zstandard',
+         94 => 'MP3',
+         95 => 'XZ',
          96 => 'WinZip JPEG Compression',
          97 => 'WavPack compressed data',
          98 => 'PPMd version I, Rev 1',
@@ -114,9 +117,11 @@ my %Lookup = (
     ZIP_END_CENTRAL_HDR_SIG,       \&EndCentralHeader,
     ZIP64_END_CENTRAL_REC_HDR_SIG, \&Zip64EndCentralHeader,
     ZIP64_END_CENTRAL_LOC_HDR_SIG, \&Zip64EndCentralLocator,
-    
-    # TODO - Archive Encryption Headers
+
+    # TODO - Archive Encryption Headers & digital signature
     #ZIP_ARCHIVE_EXTRA_DATA_RECORD_SIG
+    #ZIP_DIGITAL_SIGNATURE_SIG
+    #ZIP_ARCHIVE_EXTRA_DATA_SIG
 );
 
 my %Extras = (
@@ -135,7 +140,10 @@ my %Extras = (
       0x0017,  ['Strong Encryption Header', undef],
       0x0018,  ['Record Management Controls', undef],
       0x0019,  ['PKCS#7 Encryption Recipient Certificate List', undef],
-      
+      0x0020,  ['Reserved for Timestamp record', undef],
+      0x0021,  ['Policy Decryption Key Record', undef],
+      0x0022,  ['Smartcrypt Key Provider Record', undef],
+      0x0023,  ['Smartcrypt Policy Key Data Record', undef],
 
       # The Header ID mappings defined by Info-ZIP and third parties are:
 
@@ -174,13 +182,13 @@ my %Extras = (
       0x7875,  ['Unix Extra Type 3', \&decode_ux],
       0x9901,  ['AES Encryption', \&decode_AES],
       0xa11e,  ['Data Stream Alignment', undef],
-      0xA220,  ['Open Packaging Growth Hint', undef ],
+      0xA220,  ['Open Packaging Growth Hint', \&decode_GrowthHint ],
       0xCAFE,  ['Java Executable', \&decode_Java_exe],
       0xfb4a,  ['SMS/QDOS', undef],
 
        );
 
-my $VERSION = "1.11" ;
+my $VERSION = "2.01" ;
 
 my $FH;
 
@@ -237,23 +245,23 @@ sub setupFormat
 {
     my $wantVerbose = shift ;
     my $nibbles = shift;
-    
+
     my $width = '@' . ('>' x ($nibbles -1));
     my $space = " " x length($width);
 
     my $fmt ;
-    
+
     if ($wantVerbose) {
-        
+
         $FMT1 = "
         format STDOUT =
 $width $width ^<<<<<<<<<<<^<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 \$OFF,     \$LENGTH,  \$CONTENT, \$TEXT,               \$VALUE
 $space $space ^<<<<<<<<<<<^<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
                     \$CONTENT, \$TEXT,               \$VALUE
-.                    
+.
 ";
-                    
+
         $FMT2 = "
         format STDOUT =
 $width $width ^<<<<<<<<<<<  ^<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@@ -285,15 +293,15 @@ $space   ^<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
     }
 
     eval "$FMT1";
-    
+
     $| = 1;
 
 }
 
 sub mySpr
-{    
+{
     my $format = shift ;
-    
+
     return "" if ! defined $format;
     return $format unless @_ ;
     return sprintf $format, @_ ;
@@ -304,13 +312,13 @@ sub out0
     my $size = shift;
     my $text = shift;
     my $format = shift;
-    
+
     $OFF     = prOff($size);
     $LENGTH  = offset($size) ;
     $CONTENT = '...';
     $TEXT    = $text;
     $VALUE   = mySpr $format,  @_;
-       
+
     write;
 
     skip($FH, $size);
@@ -328,10 +336,10 @@ sub hexDump
 {
     my $input = shift;
 
-    my $out = unpack('H*', $input) ;   
+    my $out = unpack('H*', $input) ;
     $out =~ s#(..)# $1#g ;
     $out =~ s/^ //;
-    $out = uc $out;  
+    $out = uc $out;
 
     return $out;
 }
@@ -341,7 +349,7 @@ sub out
     my $data = shift;
     my $text = shift;
     my $format = shift;
-    
+
     my $size = length($data) ;
 
     $OFF     = prOff($size);
@@ -349,7 +357,7 @@ sub out
     $CONTENT = hexDump($data);
     $TEXT    = $text;
     $VALUE   = mySpr $format,  @_;
-       
+
     no warnings;
 
     write;
@@ -359,12 +367,12 @@ sub out1
 {
     my $text = shift;
     my $format = shift;
-      
+
     $OFF     = '';
     $LENGTH  = '' ;
     $CONTENT = '';
-    $TEXT    = $text;    
-    $VALUE   = mySpr $format,  @_; 
+    $TEXT    = $text;
+    $VALUE   = mySpr $format,  @_;
 
     write;
 }
@@ -374,13 +382,13 @@ sub out2
     my $data = shift ;
     my $text = shift ;
     my $format = shift;
-      
+
     my $size = length($data) ;
     $OFF     = prOff($size);
     $LENGTH  = offset($size);
     $CONTENT = hexDump($data);
-    $TEXT    = $text;    
-    $VALUE   = mySpr $format,  @_; 
+    $TEXT    = $text;
+    $VALUE   = mySpr $format,  @_;
 
     no warnings;
     eval "$FMT2";
@@ -412,7 +420,7 @@ sub outer
     my $cb2  = shift ;
 
 
-    myRead(my $buff, $size);    
+    myRead(my $buff, $size);
     my (@value) = unpack $unpack, $buff;
     my $hex = Value($unpack,  @value);
 
@@ -434,7 +442,7 @@ sub outer
 
     $cb2->(@value)
         if defined $cb2 ;
-    
+
     return $value[0];
 }
 
@@ -584,7 +592,7 @@ sub Value_VV64
 sub read_U64
 {
     my $b ;
-    myRead($b, 8);    
+    myRead($b, 8);
     my ($lo, $hi) = unpack ("V V" , $b);
     no warnings 'uninitialized';
     return ($b, new U64 $hi, $lo);
@@ -593,7 +601,7 @@ sub read_U64
 sub read_VV
 {
     my $b ;
-    myRead($b, 8);    
+    myRead($b, 8);
     my ($lo, $hi) = unpack ("V V" , $b);
     no warnings 'uninitialized';
     return ($b, $hi * (0xFFFFFFFF+1) + $lo);
@@ -621,27 +629,82 @@ sub read_C
     return ($b, unpack "C", $b);
 }
 
+sub seekTo
+{
+    my $offset = shift ;
+    my $loc = shift ;
 
-my $opt_verbose = 0;
-while (@ARGV && $ARGV[0] =~ /^-/)
+    $loc = SEEK_SET
+        if ! defined $loc ;
+
+    $FH->seek($offset, $loc);
+    $OFFSET = new U64($offset);
+}
+
+sub scanForSignature
 {
-    my $opt = shift;
-    
-    if ($opt =~ /^-h/i)
-    {
-        Usage();
-        exit;
-    }
-    elsif ($opt =~ /^-v/i)
+    my %sigs =
+        map { $_ => 1         }
+        map { substr $_, 2, 2 } # don't want the initial "PK"
+        map { pack "V", $_    }
+        (
+                ZIP_LOCAL_HDR_SIG                 ,
+                ZIP_DATA_HDR_SIG                  ,
+                ZIP_CENTRAL_HDR_SIG               ,
+                ZIP_END_CENTRAL_HDR_SIG           ,
+                ZIP64_END_CENTRAL_REC_HDR_SIG     ,
+                ZIP64_END_CENTRAL_LOC_HDR_SIG     ,
+                # ZIP_ARCHIVE_EXTRA_DATA_SIG        ,
+                # ZIP_DIGITAL_SIGNATURE_SIG         ,
+                # ZIP_ARCHIVE_EXTRA_DATA_RECORD_SIG ,
+        );
+
+    my $start = $FH->tell();
+
+    my $last = '';
+    my $buffer ;
+    while ($FH->read($buffer, 1024 * 1000))
     {
-        $opt_verbose = 1;
-    }
-    else {
-        Usage();
+        my $combine = substr($last, -4) . $buffer ;
+        $last = $buffer;
+        my $ix = index($combine, "PK") ;
+
+        next
+            if $ix == -1;
+
+        my $rest = substr($combine, $ix+2, 2);
+
+        next
+            unless length $rest == 2 && $sigs{$rest} ;
+
+        my $v = unpack("v", $rest) ;
+
+        # possible match
+        my $here = $FH->tell();
+        seekTo($here - length($combine) + $ix);
+
+        return 1;
     }
+
+    return 0;
 }
 
-Usage() unless @ARGV == 1;
+my $is64In32 = 0;
+
+my $opt_verbose = 0;
+my $opt_scan = 0;
+
+$Getopt::Long::bundling = 1 ;
+
+GetOptions("h"       => \&Usage,
+           "v"       => \$opt_verbose,
+           "scan"    => \$opt_scan,
+           "version" => sub { print "$VERSION\n"; exit },
+    )
+  or Usage("Invalid command line option\n");
+
+
+Usage("No zipfile") unless @ARGV == 1;
 
 my $filename = shift @ARGV;
 
@@ -655,9 +718,9 @@ $FH = new IO::File "<$filename"
     or die "Cannot open $filename: $!\n";
 
 
-my $FILELEN = -s $filename ;    
-$TRAILING = -s $filename ;    
-$NIBBLES = U64::nibbles(-s $filename) ; 
+my $FILELEN = -s $filename ;
+$TRAILING = -s $filename ;
+$NIBBLES = U64::nibbles(-s $filename) ;
 #$NIBBLES = int ($NIBBLES / 4) + ( ($NIBBLES % 4) ? 1 : 0 );
 #$NIBBLES = 4 * $NIBBLES;
 # Minimum of 4 nibbles
@@ -678,8 +741,28 @@ if(0)
     $FH->seek(0, SEEK_SET) ;
 }
 
+my @Messages = ();
 
-our ($CdExists, @CentralDirectory) = scanCentralDirectory($FH);
+if ($opt_scan)
+{
+
+    while(scanForSignature())
+    {
+        my $here = $FH->tell();
+
+        my ($buffer, $signature) = read_V();
+        my $handler = $Lookup{$signature};
+        $handler->($signature, $buffer);
+
+        seekTo($here + 4) ;
+    }
+
+    dislayMessages();
+    exit;
+
+}
+
+our ($CdExists, $CdOffset, @CentralDirectory) = scanCentralDirectory($FH);
 
 die "No Central Directory records found\n"
     if ! $CdExists ;
@@ -690,6 +773,9 @@ $FH->seek(0, SEEK_SET) ;
 outSomeData($START, "PREFIX DATA")
     if defined $START && $START > 0 ;
 
+my $skippedFrom = 0 ;
+my $skippedContent = 0 ;
+
 while (1)
 {
     last if $FH->eof();
@@ -712,8 +798,8 @@ while (1)
             # Should be at offset that central directory says
             my $locOffset = $CentralDirectory[0][0];
             my $delta = $locOffset - $here ;
-            
-            if ($here  < $locOffset ) {
+
+            if ($here + 4 == $locOffset ) {
                 for (0 .. 3) {
                     $FH->ungetc(ord(substr($buffer, $_, 1)))
                 }
@@ -722,18 +808,55 @@ while (1)
             }
         }
 
-        printf "\n\nUnexpecded END at offset %08X, value %s\n", $here, Value_V($signature);
-        last;    
+
+        if ($here < $CdOffset)
+        {
+            # next
+            #     if scanForSignature() ;
+
+            $skippedFrom = $FH->tell() ;
+            $skippedContent = $CdOffset - $skippedFrom ;
+
+            print "\nWARNING!\nZip local header not found.\n";
+            printf "Skipping 0x%x bytes to Central Directory...\n", $skippedContent;
+
+            push @Messages,
+                sprintf("Expected Zip header not found at offset 0x%X, ", $skippedFrom) .
+                sprintf("skipped 0x%X bytes\n", $skippedContent);
+
+            seekTo($CdOffset);
+
+            next;
+        }
+        else
+        {
+            printf "\n\nUnexpected END at offset %08X, value %s\n", $here, Value_V($signature);
+
+            last;
+        }
     }
 
     $ZIP64 = 0 if $signature != ZIP_DATA_HDR_SIG ;
     $handler->($signature, $buffer);
 }
 
-print "Done\n";
+
+dislayMessages();
 
 exit ;
 
+sub dislayMessages
+{
+    if (@Messages)
+    {
+        my $count = scalar @Messages ;
+        print "\nWARNINGS\n\n";
+        print "* $_\n" for @Messages ;
+    }
+
+    print "Done\n";
+}
+
 sub compressionMethod
 {
     my $id = shift ;
@@ -742,18 +865,18 @@ sub compressionMethod
 
 sub LocalHeader
 {
-    my $signature = shift ;  
-    my $data = shift ;  
-        
+    my $signature = shift ;
+    my $data = shift ;
+
     print "\n";
     ++ $LocalHeaderCount;
     out $data, "LOCAL HEADER #" . sprintf("%X", $LocalHeaderCount) , Value_V($signature);
 
     my $buffer;
 
-    my ($loc, $CDcompressedLength) = @{ shift @CentralDirectory };
-    # print "LocalHeader loc $loc CDL $CDcompressedLength\n";
-    # TODO - add test to check that the loc from central header matches
+    my ($loc, $CDcompressedLength) ;
+    ($loc, $CDcompressedLength) = @{ shift @CentralDirectory }
+        if ! $opt_scan ;
 
     out_C  "Extract Zip Spec", \&decodeZipVer;
     out_C  "Extract OS", \&decodeOS;
@@ -762,7 +885,7 @@ sub LocalHeader
     my ($bcm, $compressedMethod) = read_v();
 
     out $bgp, "General Purpose Flag", Value_v($gpFlag) ;
-    GeneralPurposeBits($compressedMethod, $gpFlag);    
+    GeneralPurposeBits($compressedMethod, $gpFlag);
 
     out $bcm, "Compression Method",   compressionMethod($compressedMethod) ;
 
@@ -776,7 +899,7 @@ sub LocalHeader
 
     my $filename ;
     myRead($filename, $filenameLength);
-    out $filename, "Filename",  "'". $filename . "'";
+    outputFilename($filename);
 
     my $cl64 = new U64 $compressedLength ;
     my %ExtraContext = ();
@@ -795,10 +918,13 @@ sub LocalHeader
     $size += printLzmaProperties()
         if $compressedMethod == ZIP_CM_LZMA ;
 
+    $CDcompressedLength = $compressedLength
+        if $opt_scan ;
+
     # $CDcompressedLength->subtract($size)
         # if $size ;
     $CDcompressedLength -= $size;
-        
+
     # if ($CDcompressedLength->getHigh() || $CDcompressedLength->getLow()) {
     if ($CDcompressedLength) {
         outSomeData($CDcompressedLength, "PAYLOAD") ;
@@ -811,12 +937,26 @@ sub LocalHeader
     }
 }
 
+sub outputFilename
+{
+    my $filename = shift;
+
+    if (length $filename > 256)
+    {
+        my $f = substr($filename, 0, 256) ;
+        out $f, "Filename",  "'". $f . "' ...";
+    }
+    else
+    {
+        out $filename, "Filename",  "'". $filename . "'";
+    }
+}
 
 sub CentralHeader
 {
     my $signature = shift ;
-    my $data = shift ;  
-        
+    my $data = shift ;
+
     ++ $CentralHeaderCount;
     print "\n";
     out $data, "CENTRAL HEADER #" . sprintf("%X", $CentralHeaderCount) . "", Value_V($signature);
@@ -831,7 +971,7 @@ sub CentralHeader
     my ($bcm, $compressedMethod) = read_v();
 
     out $bgp, "General Purpose Flag", Value_v($gpFlag) ;
-    GeneralPurposeBits($compressedMethod, $gpFlag);    
+    GeneralPurposeBits($compressedMethod, $gpFlag);
 
     out $bcm, "Compression Method", compressionMethod($compressedMethod) ;
 
@@ -849,24 +989,25 @@ sub CentralHeader
     out1 "[Bit 0]",  $int_file_attrib & 1 ? "1 Text Data" : "0 'Binary Data'";
 
     my $ext_file_attrib    = out_V "Ext File Attributes";
-    out1 "[Bit 0]",  "Read-Only" 
+    out1 "[Bit 0]",  "Read-Only"
         if $ext_file_attrib & 0x01 ;
-    out1 "[Bit 1]",  "Hidden" 
+    out1 "[Bit 1]",  "Hidden"
         if $ext_file_attrib & 0x02 ;
-    out1 "[Bit 2]",  "System" 
+    out1 "[Bit 2]",  "System"
         if $ext_file_attrib & 0x04 ;
-    out1 "[Bit 3]",  "Label" 
+    out1 "[Bit 3]",  "Label"
         if $ext_file_attrib & 0x08 ;
-    out1 "[Bit 4]",  "Directory" 
+    out1 "[Bit 4]",  "Directory"
         if $ext_file_attrib & 0x10 ;
-    out1 "[Bit 5]",  "Archive" 
+    out1 "[Bit 5]",  "Archive"
         if $ext_file_attrib & 0x20 ;
 
     my $lcl_hdr_offset     = out_V "Local Header Offset";
 
     my $filename ;
     myRead($filename, $filenameLength);
-    out $filename, "Filename",  "'". $filename . "'";
+    outputFilename($filename);
+
 
     my %ExtraContext = ();
     if ($extraLength)
@@ -874,7 +1015,7 @@ sub CentralHeader
         my @z64 = ($uncompressedLength, $compressedLength, $lcl_hdr_offset, $disk_start);
         $ExtraContext{Zip64} = \@z64 ;
         $ExtraContext{InCentralDir} = 1;
-        walkExtra($extraLength, \%ExtraContext);        
+        walkExtra($extraLength, \%ExtraContext);
     }
 
     if ($comment_length)
@@ -888,25 +1029,25 @@ sub CentralHeader
 sub decodeZipVer
 {
     my $ver = shift ;
-    
+
     my $sHi = int($ver /10) ;
     my $sLo = $ver % 10 ;
-    
-    #out1 "Zip Spec", "$sHi.$sLo";       
-    "$sHi.$sLo";       
+
+    #out1 "Zip Spec", "$sHi.$sLo";
+    "$sHi.$sLo";
 }
 
 sub decodeOS
 {
     my $ver = shift ;
-    
+
     $OS_Lookup{$ver} || "Unknown" ;
 }
 
 sub Zip64EndCentralHeader
 {
-    my $signature = shift ;    
-    my $data = shift ;  
+    my $signature = shift ;
+    my $data = shift ;
 
     print "\n";
     out $data, "ZIP64 END CENTRAL DIR RECORD", Value_V($signature);
@@ -914,7 +1055,7 @@ sub Zip64EndCentralHeader
     my $buff;
     myRead($buff, 8);
 
-    out $buff, "Size of record",       unpackValue_VV($buff);    
+    out $buff, "Size of record",       unpackValue_VV($buff);
 
     my $size  = Value_VV64($buff);
 
@@ -929,30 +1070,32 @@ sub Zip64EndCentralHeader
     out_VV "Size of Central Dir";
     out_VV "Offset to Central dir";
 
-    # TODO - 
-    die "Unsupported Size ($size) in Zip64EndCentralHeader\n" 
-        if $size !=  44;
+    # TODO -
+    if ($size != 44)
+    {
+        push @Messages,  "Unsupported Size field in Zip64EndCentralHeader: should be 44, got $size\n"
+    }
 }
 
 
 sub Zip64EndCentralLocator
 {
     my $signature = shift ;
-    my $data = shift ;  
-        
+    my $data = shift ;
+
     print "\n";
     out $data, "ZIP64 END CENTRAL DIR LOCATOR", Value_V($signature);
-    
+
     out_V  "Central Dir Disk no";
     out_VV "Offset to Central dir";
-    out_V  "Total no of Disks";    
+    out_V  "Total no of Disks";
 }
 
 sub EndCentralHeader
 {
-    my $signature = shift ;  
-    my $data = shift ;  
-        
+    my $signature = shift ;
+    my $data = shift ;
+
     print "\n";
     out $data, "END CENTRAL HEADER", Value_V($signature);
 
@@ -966,31 +1109,31 @@ sub EndCentralHeader
 
     if ($comment_length)
     {
-        my $comment ;        
+        my $comment ;
         myRead($comment, $comment_length);
         out $comment, "Comment", "'$comment'";
-    }    
+    }
 }
 
 sub DataHeader
 {
-    my $signature = shift ;  
-    my $data = shift ;  
-        
+    my $signature = shift ;
+    my $data = shift ;
+
     print "\n";
     out $data, "STREAMING DATA HEADER", Value_V($signature);
-    
+
     out_V "CRC";
-    
+
     if ($ZIP64)
     {
         out_VV "Compressed Length" ;
-        out_VV "Uncompressed Length" ;        
+        out_VV "Uncompressed Length" ;
     }
     else
     {
         out_V "Compressed Length" ;
-        out_V "Uncompressed Length" ;  
+        out_V "Uncompressed Length" ;
     }
 }
 
@@ -1000,8 +1143,8 @@ sub GeneralPurposeBits
     my $method = shift;
     my $gp = shift;
 
-    out1 "[Bit  0]", "1 'Encryption'" if $gp & ZIP_GP_FLAG_ENCRYPTED_MASK;   
-    
+    out1 "[Bit  0]", "1 'Encryption'" if $gp & ZIP_GP_FLAG_ENCRYPTED_MASK;
+
     my %lookup = (
         0 =>    "Normal Compression",
         1 =>    "Maximum Compression",
@@ -1012,8 +1155,8 @@ sub GeneralPurposeBits
     if ($method == ZIP_CM_DEFLATE)
     {
         my $mid = $gp & 0x03;
-        
-        out1 "[Bits 1-2]", "$mid '$lookup{$mid}'";        
+
+        out1 "[Bits 1-2]", "$mid '$lookup{$mid}'";
     }
 
     if ($method == ZIP_CM_LZMA)
@@ -1025,23 +1168,22 @@ sub GeneralPurposeBits
             out1 "[Bit 1]", "0 'LZMA EOS Marker Not Present'" ;
         }
     }
-    
+
     if ($method == ZIP_CM_IMPLODE) # Imploding
     {
         out1 "[Bit 1]", ($gp & 1 ? "1 '8k" : "0 '4k") . " Sliding Dictionary'" ;
-        out1 "[Bit 2]", ($gp & 2 ? "1 '3" : "0 '2"  ) . " Shannon-Fano
-        Trees'" ;
-    }    
-    
+        out1 "[Bit 2]", ($gp & 2 ? "1 '3" : "0 '2"  ) . " Shannon-Fano Trees'" ;
+    }
+
     out1 "[Bit  3]", "1 'Streamed'"           if $gp & ZIP_GP_FLAG_STREAMING_MASK;
     out1 "[Bit  4]", "1 'Enhanced Deflating'" if $gp & 1 << 4;
     out1 "[Bit  5]", "1 'Compressed Patched'" if $gp & 1 << 5 ;
     out1 "[Bit  6]", "1 'Strong Encryption'"  if $gp & ZIP_GP_FLAG_STRONG_ENCRYPTED_MASK;
-    out1 "[Bit 11]", "1 'Language Encoding'"  if $gp & ZIP_GP_FLAG_LANGUAGE_ENCODING;  
-    out1 "[Bit 12]", "1 'Pkware Enhanced Compression'"  if $gp & 1 <<12 ; 
-    out1 "[Bit 13]", "1 'Encrypted Central Dir'"  if $gp & 1 <<13 ; 
-    
-    return ();    
+    out1 "[Bit 11]", "1 'Language Encoding'"  if $gp & ZIP_GP_FLAG_LANGUAGE_ENCODING;
+    out1 "[Bit 12]", "1 'Pkware Enhanced Compression'"  if $gp & 1 <<12 ;
+    out1 "[Bit 13]", "1 'Encrypted Central Dir'"  if $gp & 1 <<13 ;
+
+    return ();
 }
 
 
@@ -1057,7 +1199,7 @@ sub seekSet
     else {
         seek($fh, $size, SEEK_SET);
     }
-    
+
 }
 
 sub skip
@@ -1072,7 +1214,7 @@ sub skip
     else {
         seek($fh, $size, SEEK_CUR);
     }
-    
+
 }
 
 
@@ -1109,50 +1251,51 @@ sub myRead
 sub walkExtra
 {
     my $XLEN = shift;
-    my $context = shift; 
+    my $context = shift;
 
     my $buff ;
     my $offset = 0 ;
-    
+
     my $id;
     my $subLen;
     my $payload ;
-    
-    my $count = 0 ;
-    
-    if ($XLEN < ZIP_EXTRA_SUBFIELD_ID_SIZE + ZIP_EXTRA_SUBFIELD_LEN_SIZE)
-    {
-        # Android zipalign is prime candidate for this non-standard extra field.
-        myRead($payload, $XLEN); 
-        my $data = hexDump($payload);
-        
-        out $payload, "Malformed Extra Data", $data;
 
-        return undef;
-    }
+    my $count = 0 ;
 
     while ($offset < $XLEN) {
 
         ++ $count;
-        
-        return undef
-            if $offset + ZIP_EXTRA_SUBFIELD_HEADER_SIZE  > $XLEN ;
 
-        myRead($id, ZIP_EXTRA_SUBFIELD_ID_SIZE); 
+        # Detect if there is not enough data for an extra ID and length.
+        # Android zipalign and zipflinger are prime candidates for these
+        # non-standard extra sub-fields.
+        my $remaining = $XLEN - $offset;
+        if ($remaining < ZIP_EXTRA_SUBFIELD_HEADER_SIZE) {
+            # There is not enough. Consume whatever is there and return so parsing
+            # can continue.
+            myRead($payload, $remaining);
+            my $data = hexDump($payload);
+
+            out $payload, "Malformed Extra Data", $data;
+
+            return undef;
+        }
+
+        myRead($id, ZIP_EXTRA_SUBFIELD_ID_SIZE);
         $offset += ZIP_EXTRA_SUBFIELD_ID_SIZE;
         my $lookID = unpack "v", $id ;
         my ($who, $decoder) =  @{ defined $Extras{$lookID} ? $Extras{$lookID} : ['', undef] };
         #my ($who, $decoder) =  @{ $Extras{unpack "v", $id} || ['', undef] };
-        
+
         $who = "$id: $who"
             if $id =~ /\w\w/ ;
 
-        $who = "'$who'";    
+        $who = "'$who'";
         out $id, "Extra ID #" . Value_v($count), unpackValue_v($id) . " $who" ;
-        
-        myRead($buff, ZIP_EXTRA_SUBFIELD_LEN_SIZE); 
-        $offset += ZIP_EXTRA_SUBFIELD_LEN_SIZE;        
-        
+
+        myRead($buff, ZIP_EXTRA_SUBFIELD_LEN_SIZE);
+        $offset += ZIP_EXTRA_SUBFIELD_LEN_SIZE;
+
         $subLen =  unpack("v", $buff);
         out2 $buff, "Length", Value_v($subLen) ;
 
@@ -1161,24 +1304,27 @@ sub walkExtra
 
         if (! defined $decoder)
         {
-            myRead($payload, $subLen);
-            my $data = hexDump($payload);
-        
-            out2 $payload, "Extra Payload", $data;
+            if ($subLen)
+            {
+                myRead($payload, $subLen);
+                my $data = hexDump($payload);
+
+                out2 $payload, "Extra Payload", $data;
+            }
         }
         else
         {
             $decoder->($subLen, $context) ;
         }
-               
+
         $offset += $subLen ;
     }
-        
+
     return undef ;
 }
 
 
-sub full32 
+sub full32
 {
     return $_[0] == 0xFFFFFFFF ;
 }
@@ -1187,8 +1333,8 @@ sub decode_Zip64
 {
     my $len = shift;
     my $context = shift;
-    
-    my $z64Data = $context->{Zip64};    
+
+    my $z64Data = $context->{Zip64};
 
     $ZIP64 = 1;
 
@@ -1201,11 +1347,11 @@ sub decode_Zip64
     }
 
     if (full32 $z64Data->[2] ) {
-        out_VV "  Offset to Local Dir";        
+        out_VV "  Offset to Local Dir";
     }
 
     if ($z64Data->[3] == 0xFFFF ) {
-        out_V "  Disk Number";        
+        out_V "  Disk Number";
     }
 }
 
@@ -1222,7 +1368,7 @@ sub Ntfs2Unix
     my $elapse = $u64->get64bit();
     my $ns = ($elapse % 10000000) * 100;
     $elapse = int ($elapse/10000000);
-    return "$hex '" . localtime($elapse) . 
+    return "$hex '" . localtime($elapse) .
            " " . sprintf("%0dns'", $ns);
 }
 
@@ -1234,7 +1380,7 @@ sub decode_NTFS_Filetimes
     out_V "  Reserved";
     out_v "  Tag1";
     out_v "  Size1" ;
-    
+
     my ($m, $s1) = read_U64;
     out $m, "  Mtime", Ntfs2Unix($m, $s1);
 
@@ -1256,24 +1402,24 @@ sub decode_UT
 {
     my $len = shift;
     my $context = shift;
-        
+
     my ($data, $flags) = read_C();
 
     my $f = Value_C $flags;
     $f .= " mod"    if $flags & 1;
     $f .= " access" if $flags & 2;
     $f .= " change" if $flags & 4;
-    
+
     out $data, "  Flags", "'$f'";
-    
+
     -- $len;
-    
+
     if ($flags & 1)
     {
         my ($data, $time) = read_V();
 
         out2 $data, "Mod Time",    Value_V($time) . " " . getTime($time) ;
-        
+
         $len -= 4 ;
     }
 
@@ -1281,15 +1427,15 @@ sub decode_UT
       if ($flags & 2 && $len > 0 )
       {
           my ($data, $time) = read_V();
-  
+
           out2 $data, "Access Time",    Value_V($time) . " " . getTime($time) ;
           $len -= 4 ;
       }
-  
+
       if ($flags & 4 && $len > 0)
       {
           my ($data, $time) = read_V();
-  
+
           out2 $data, "Change Time",    Value_V($time) . " " . getTime($time) ;
       }
 }
@@ -1302,25 +1448,43 @@ sub decode_AES
     my $context = shift;
 
     return if $len == 0 ;
-    
+
     my %lookup = ( 1 => "AE-1", 2 => "AE-2");
     out_v "  Vendor Version", sub {  $lookup{$_[0]} || "Unknown"  } ;
-    
-    my $id ; 
+
+    my $id ;
     myRead($id, 2);
     out $id, "  Vendor ID", unpackValue_v($id) . " '$id'";
-    
+
     my %strengths = (1 => "128-bit encryption key",
                      2 => "192-bit encryption key",
                      3 => "256-bit encryption key",
                     );
-    
-    my $strength = out_C "  Encryption Strength", sub {$strengths{$_[0]} || "Unknown" } ; 
+
+    my $strength = out_C "  Encryption Strength", sub {$strengths{$_[0]} || "Unknown" } ;
 
     my ($bmethod, $method) = read_v();
     out $bmethod, "  Compression Method", compressionMethod($method) ;
 
-    $context->{AesStrength} = $strength ;     
+    $context->{AesStrength} = $strength ;
+}
+
+sub decode_GrowthHint
+{
+    my $len = shift;
+    my $context = shift;
+    my $inCentralHdr = $context->{InCentralDir} ;
+
+    return if $len == 0 ;
+
+    out_v "  Signature" ;
+    out_v "  Initial Value";
+
+    my $padding;
+    myRead($padding, $len - 4);
+    my $data = hexDump($padding);
+
+    out2 $padding, "Padding", $data;
 }
 
 sub decode_UX
@@ -1329,7 +1493,7 @@ sub decode_UX
     my $context = shift;
     my $inCentralHdr = $context->{InCentralDir} ;
 
-    return if $len == 0 ;    
+    return if $len == 0 ;
 
     my ($data, $time) = read_V();
     out2 $data, "Access Time",    Value_V($time) . " " . getTime($time) ;
@@ -1339,7 +1503,7 @@ sub decode_UX
 
     if (! $inCentralHdr ) {
         out_v "  UID" ;
-        out_v "  GID";    
+        out_v "  GID";
     }
 }
 
@@ -1348,9 +1512,9 @@ sub decode_Ux
     my $len = shift;
     my $context = shift;
 
-    return if $len == 0 ;    
+    return if $len == 0 ;
     out_v "  UID" ;
-    out_v "  GID";    
+    out_v "  GID";
 }
 
 sub decodeLitteEndian
@@ -1369,7 +1533,7 @@ sub decodeLitteEndian
     my $got = 0 ;
     my $shift = 0;
 
-    #hexDump 
+    #hexDump
     #reverse
     #my @a =unpack "C*", $value;
     #@a = reverse @a;
@@ -1379,7 +1543,7 @@ sub decodeLitteEndian
     {
         $got = ($got << 8) + $_ ;
     }
-    
+
     return $got ;
 }
 
@@ -1388,16 +1552,16 @@ sub decode_ux
     my $len = shift;
     my $context = shift;
 
-    return if $len == 0 ;    
+    return if $len == 0 ;
     out_C "  Version" ;
-    my $uidSize = out_C "  UID Size";    
+    my $uidSize = out_C "  UID Size";
     myRead(my $data, $uidSize);
     out2 $data, "UID", decodeLitteEndian($data);
 
-    my $gidSize = out_C "  GID Size";    
+    my $gidSize = out_C "  GID Size";
     myRead($data, $gidSize);
     out2 $data, "GID", decodeLitteEndian($data);
-    
+
 }
 
 sub decode_Java_exe
@@ -1412,13 +1576,13 @@ sub decode_up
     my $len = shift;
     my $context = shift;
 
-    
+
     out_C "  Version";
     out_V "  NameCRC32";
-    
+
     myRead(my $data, $len - 5);
-    
-    out $data, "  UnicodeName", $data;     
+
+    out $data, "  UnicodeName", $data;
 }
 
 sub decode_Xceed_unicode
@@ -1427,17 +1591,17 @@ sub decode_Xceed_unicode
     my $context = shift;
 
     my $data ;
-    
+
     # guess the fields used for this one
     myRead($data, 4);
-    out $data, "  ID", $data;     
+    out $data, "  ID", $data;
 
     out_v "  Length";
     out_v "  Null";
-    
+
     myRead($data, $len - 8);
-    
-    out $data, "  UTF16LE Name", decode("UTF16LE", $data);     
+
+    out $data, "  UTF16LE Name", decode("UTF16LE", $data);
 }
 
 
@@ -1446,18 +1610,18 @@ sub decode_NT_security
     my $len = shift;
     my $context = shift;
     my $inCentralHdr = $context->{InCentralDir} ;
-    
+
     out_V "  Uncompressed Size" ;
-    
+
     if (! $inCentralHdr) {
-  
+
         out_C "  Version" ;
-     
-        out_v "  Type";  
-        
+
+        out_v "  Type";
+
         out_V "  NameCRC32" ;
-        
-        my $plen = $len - 4 - 1 - 2 - 4;        
+
+        my $plen = $len - 4 - 1 - 2 - 4;
         myRead(my $payload, $plen);
         out $plen, "  Extra Payload", hexDump($payload);
     }
@@ -1494,7 +1658,7 @@ sub printAes
     myRead(my $salt, $saltSize{$context->{AesStrength} });
     out $salt, "AES Salt", hexDump($salt);
     myRead(my $pwv, 2);
-    out $pwv, "AES Pwd Ver", hexDump($pwv);  
+    out $pwv, "AES Pwd Ver", hexDump($pwv);
 
     return  $saltSize{$context->{AesStrength}} + 2 + 10;
 }
@@ -1527,7 +1691,7 @@ sub printLzmaProperties
     out1 "  PosStateBits",        $PosStateBits;
     out1 "  LiteralPosStateBits", $LiteralPosStateBits;
     out1 "  LiteralContextBits",  $LiteralContextBits;
-    
+
     out_V "LZMA Dictionary Size";
 
     # TODO - assumption that this is 5
@@ -1559,7 +1723,7 @@ sub scanCentralDirectory
 
     # Now walk the Central Directory Records
     my $buffer ;
-    while ($fh->read($buffer, 46) == 46  && 
+    while ($fh->read($buffer, 46) == 46  &&
            unpack("V", $buffer) == ZIP_CENTRAL_HDR_SIG) {
 
         my $compressedLength   = unpack("V", substr($buffer, 20, 4));
@@ -1569,20 +1733,17 @@ sub scanCentralDirectory
         my $comment_length     = unpack("v", substr($buffer, 32, 2));
         my $locHeaderOffset    = unpack("V", substr($buffer, 42, 4));
 
-        $START = $locHeaderOffset
-            if ! defined $START;
-
         skip($fh, $filename_length ) ;
 
         if ($extra_length)
         {
             $fh->read(my $extraField, $extra_length) ;
-            # $self->smartReadExact(\$extraField, $extra_length);               
+            # $self->smartReadExact(\$extraField, $extra_length);
 
             # Check for Zip64
             # my $zip64Extended = findID("\x01\x00", $extraField);
             my $zip64Extended = findID(0x0001, $extraField);
-            
+
             if ($zip64Extended)
             {
                 if ($uncompressedLength == 0xFFFFFFFF)
@@ -1594,14 +1755,14 @@ sub scanCentralDirectory
                 {
                     $compressedLength = Value_VV64  substr($zip64Extended, 0, 8, "");
                     # $compressedLength = unpack "Q<", substr($zip64Extended, 0, 8, "");
-                } 
+                }
                 if ($locHeaderOffset == 0xFFFFFFFF)
                 {
                     $locHeaderOffset = Value_VV64  substr($zip64Extended, 0, 8, "");
                     # $locHeaderOffset = unpack "Q<", substr($zip64Extended, 0, 8, "");
-                }                         
-            }                
-        }        
+                }
+            }
+        }
 
         my $got = [$locHeaderOffset, $compressedLength] ;
 
@@ -1612,7 +1773,7 @@ sub scanCentralDirectory
         # if (full32 $compressedLength || full32  $locHeaderOffset) {
         #     $fh->read($buffer, $extra_length) ;
         #     # TODO - fix this
-        #     die "xxx $offset $comment_length $filename_length $extra_length" . length($buffer) 
+        #     die "xxx $offset $comment_length $filename_length $extra_length" . length($buffer)
         #         if length($buffer) != $extra_length;
         #     $got = get64Extra($buffer, full32($uncompressedLength),
         #                          $v64,
@@ -1626,7 +1787,7 @@ sub scanCentralDirectory
         # }
 
         skip($fh, $comment_length ) ;
-            
+
         push @CD, $got ;
     }
 
@@ -1634,7 +1795,12 @@ sub scanCentralDirectory
 
     # @CD = sort { $a->[0]->cmp($b->[0]) } @CD ;
     @CD = sort { $a->[0] <=> $b->[0] } @CD ;
-    return (1, @CD);
+
+    # Set the first Local File Header offset.
+    $START = $CD[0]->[0]
+        if @CD ;
+
+    return (1, $offset, @CD);
 }
 
 
@@ -1643,19 +1809,22 @@ sub offsetFromZip64
     my $fh = shift ;
     my $here = shift;
 
-    $fh->seek($here - 20, SEEK_SET) 
+    $fh->seek($here - 20, SEEK_SET)
     # TODO - fix this
         or die "xx $!" ;
 
     my $buffer;
     my $got = 0;
-    ($got = $fh->read($buffer, 20)) == 20 
+    ($got = $fh->read($buffer, 20)) == 20
     # TODO - fix this
-        or die "xxx $here $got $!" ;
+        or die "xxx
+
+
+         $here $got $!" ;
 
     if ( unpack("V", $buffer) == ZIP64_END_CENTRAL_LOC_HDR_SIG ) {
         my $cd64 = Value_VV64 substr($buffer,  8, 8);
-       
+
         $fh->seek($cd64, SEEK_SET) ;
 
         $fh->read($buffer, 4) == 4
@@ -1676,13 +1845,11 @@ sub offsetFromZip64
 
             return $cd64 ;
         }
-        
-        # TODO - fix this
-        die "zzz";
+
+        die "Cannot find 'Zip64 end of central directory record': 0x06054b50\nTry running with --scan option.\n" ;
     }
 
-    # TODO - fix this
-    die "zzz";
+    die "Cannot find signature for 'Zip64 end of central directory locator': 0x07064b50 \nTry running with --scan option.\n" ;
 }
 
 use constant Pack_ZIP_END_CENTRAL_HDR_SIG => pack("V", ZIP_END_CENTRAL_HDR_SIG);
@@ -1698,13 +1865,17 @@ sub findCentralDirectoryOffset
     $fh->seek(-22, SEEK_END) ;
     my $here = $fh->tell();
 
+    my $is64bit = $here > 0xFFFFFFFF;
+    my $over64bit = $here  & (~ 0xFFFFFFFF);
+
     my $buffer;
-    $fh->read($buffer, 22) == 22 
+    $fh->read($buffer, 22) == 22
     # TODO - fix this
         or die "xxx" ;
 
-    my $zip64 = 0;                             
+    my $zip64 = 0;
     my $centralDirOffset ;
+
     if ( unpack("V", $buffer) == ZIP_END_CENTRAL_HDR_SIG ) {
         $centralDirOffset = unpack("V", substr($buffer, 16,  4));
     }
@@ -1721,7 +1892,7 @@ sub findCentralDirectoryOffset
                 $seekTo = 0;
                 $want = $fileLen ;
             }
-            $fh->seek( $seekTo, SEEK_SET) 
+            $fh->seek( $seekTo, SEEK_SET)
             # TODO - fix this
                 or die "xxx $!" ;
             my $got;
@@ -1749,8 +1920,22 @@ sub findCentralDirectoryOffset
         }
     }
 
-    $centralDirOffset = offsetFromZip64($fh, $here)
-        if full32 $centralDirOffset ;
+    if (full32 $centralDirOffset)
+    {
+        $centralDirOffset = offsetFromZip64($fh, $here)
+    }
+    elsif ($is64bit)
+    {
+        # use-case is where a 64-bit zip file doesn't use the 64-bit
+        # extensions.
+        print "EOCD not 64-bit $centralDirOffset ($here)\n" ;
+
+        push @Messages,
+            sprintf "Zip file > 4Gig. Expected 'Offset to Central Dir' to be 0xFFFFFFFF, got 0x%X\n", $centralDirOffset;
+
+        $centralDirOffset += $over64bit;
+        $is64In32 = 1;
+    }
 
     return $centralDirOffset ;
 }
@@ -1768,7 +1953,7 @@ sub findID
         return undef
             if $offset + ZIP_EXTRA_SUBFIELD_HEADER_SIZE  > $XLEN ;
 
-        my $id = substr($data, $offset, ZIP_EXTRA_SUBFIELD_ID_SIZE);    
+        my $id = substr($data, $offset, ZIP_EXTRA_SUBFIELD_ID_SIZE);
         $id = unpack("v", $id);
         $offset += ZIP_EXTRA_SUBFIELD_ID_SIZE;
 
@@ -1784,7 +1969,7 @@ sub findID
 
         $offset += $subLen ;
     }
-        
+
     return undef ;
 }
 
@@ -1830,7 +2015,16 @@ sub _dosToUnixTime
             $low  = shift ;
         }
         elsif (@_ == 1) {
-            $low  = shift ;
+            my $value = shift ;
+            if ($value > MAX32)
+            {
+                $high = $value >> 32 ;
+                $low  = $value & MAX32;
+            }
+            else
+            {
+                $low  = $value ;
+            }
         }
 
         bless [$low, $high], $class;
@@ -1909,7 +2103,7 @@ sub _dosToUnixTime
             $self->[HIGH] += $value->[HIGH] ;
             $value = $value->[LOW];
         }
-         
+
         my $available = MAX32 - $self->[LOW] ;
 
         if ($value > $available) {
@@ -1958,7 +2152,7 @@ sub _dosToUnixTime
         {
             $self->[LOW] >>= 1;
             $self->[LOW] |= 0x80000000
-                if $self->[HIGH] & 1 ; 
+                if $self->[HIGH] & 1 ;
             $self->[HIGH] >>= 1;
         }
     }
@@ -2002,7 +2196,7 @@ sub _dosToUnixTime
 
         return "High [$self->[HIGH]], Low [$self->[LOW]]";
     }
-    
+
     sub equal
     {
         my $self = shift;
@@ -2032,7 +2226,7 @@ sub _dosToUnixTime
             return $self->[LOW] - $other->[LOW] ;
         }
     }
-    
+
     sub nibbles
     {
         my @nibbles = (
@@ -2069,6 +2263,13 @@ sub _dosToUnixTime
 
 sub Usage
 {
+    if (@_)
+    {
+        warn "$_\n"
+        for @_  ;
+        warn "\n";
+    }
+
     die <<EOM;
 zipdetails [OPTIONS] file
 
@@ -2077,16 +2278,20 @@ Display details about the internal structure of a Zip file.
 This is zipdetails version $VERSION
 
 OPTIONS
-     -h     display help
-     -v     Verbose - output more stuff
-    
-Copyright (c) 2011-2019 Paul Marquess. All rights reserved.
+     -h        display help
+     --scan    enable scannng mode.
+               Blindly scan the file looking for zip headers
+               Expect false-positives.
+     -v        Verbose - output more stuff
+     --version Print version number
+
+Copyright (c) 2011-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 EOM
 
-        
+
 }
 
 __END__
@@ -2097,33 +2302,75 @@ zipdetails - display the internal structure of zip files
 
 =head1 SYNOPSIS
 
-    zipdetails [-v] zipfile.zip
-       zipdetails -h
+    zipdetails [-v][--scan] zipfile.zip
+    zipdetails -h
+    zipdetails --version
 
 =head1 DESCRIPTION
 
-Zipdetails displays information about the internal record structure of the
-zip file. It is not concerned with displaying any details of the compressed
+Zipdetails displays information about the internal record structure of zip
+files. It is not concerned with displaying any details of the compressed
 data stored in the zip file.
 
 The program assumes prior understanding of the internal structure of a Zip
 file. You should have a copy of the Zip APPNOTE file at hand to help
 understand the output from this program (L<SEE ALSO> for details).
 
+=head2 Default Behaviour
+
+By default the program expects to be given a well-formed zip file.  It will
+navigate the Zip file by first parsing the zip central directory at the end
+of the file.  If that is found, it will then walk through the zip records
+starting at the beginning of the file. Any badly formed zip data structures
+encountered are likely to terminate the program.
+
+If the program finds any structural problems with the zip file it will
+print a summary at the end of the output report. The set of error cases
+reported is very much a work in progress, so don't rely on this feature to
+find all the possible errors in a zip file. If you have suggestions for
+use-cases where this could be enhanced please consider creating an
+enhancement request (see L<"SUPPORT">).
+
+=head2 Scan-Mode
+
+If you do have a potentially corrupt zip file, particulatly where the
+central directory at the end of the file is absent/incomplete, you can try
+usng the C<--scan> option to search for zip records that are still present.
+
+When Scan-mode is enabled, the program will walk the zip file from the
+start blindly looking for the 4-byte signatures that preceed each of the
+zip data structures. If it finds any of the recognised signatures it will
+attempt to dump the associated zip record. For very large zip files, this
+operation can take a long time to run.
+
+Note that the 4-byte signatures used in zip files can sometimes match with
+random data stored in the zip file, so care is needed interpreting the
+results.
+
 =head2 OPTIONS
 
 =over 5
 
+=item -h
+
+Display help
+
+=item --scan
+
+Walk the zip file loking for possible zip records. Can be error-prone.
+See L<"Scan-Mode">
+
 =item -v
 
-Enable Verbose mode
+Enable Verbose mode. See L<"Verbose Output">.
 
-=item -h
+=item --version
 
-Display help
+Display version number of the program and exit.
 
 =back
 
+=head2 Default Output
 
 By default zipdetails will output the details of the zip file in three
 columns.
@@ -2141,7 +2388,7 @@ This contains a textual description of the field.
 =item Column 3
 
 If the field contains a numeric value it will be displayed in hex. Zip
-stored most numbers in little-endian format - the value displayed will have
+stores most numbers in little-endian format - the value displayed will have
 the little-endian encoding removed.
 
 Next, is an optional description of what the value means.
@@ -2149,6 +2396,8 @@ Next, is an optional description of what the value means.
 
 =back
 
+=head2 Verbose Output
+
 If the C<-v> option is present, column 1 is expanded to include
 
 =over 5
@@ -2159,7 +2408,7 @@ The offset from the start of the file in hex.
 
 =item *
 
-The length of the filed in hex.
+The length of the field in hex.
 
 =item *
 
@@ -2168,23 +2417,38 @@ file.
 
 =back
 
+=head1 LIMITATIONS
+
+The following zip file features are not supported by this program:
 
-=head1 TODO 
+=over 5
+
+=item *
 
-Error handling is still a work in progress.  If the program encounters a
-problem reading a zip file it is likely to terminate with an unhelpful
-error message. 
+Multi-part archives.
+
+=item *
+
+The strong encryption features defined in the "APPNOTE" document.
+
+=back
+
+=head1 TODO
+
+Error handling is a work in progress. If the program encounters a problem
+reading a zip file it is likely to terminate with an unhelpful error
+message.
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
 =head1 SEE ALSO
 
 
-The primary reference for Zip files is the "appnote" document available at
+The primary reference for Zip files is the "APPNOTE" document available at
 L<http://www.pkware.com/documents/casestudies/APPNOTE.TXT>.
 
 An alternative reference is the Info-Zip appnote. This is available from
@@ -2203,10 +2467,9 @@ L<IO::Uncompress::Unzip>.
 
 Paul Marquess F<pmqs@cpan.org>.
 
-=head1 COPYRIGHT 
+=head1 COPYRIGHT
 
-Copyright (c) 2011-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2011-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or modify it
-under the same terms as Perl itself. 
-
+under the same terms as Perl itself.
index 4a0aae6..1290b1d 100644 (file)
@@ -7,17 +7,17 @@ use Carp ;
 use IO::Handle ;
 use Scalar::Util qw(dualvar);
 
-use IO::Compress::Base::Common 2.093 ;
-use Compress::Raw::Zlib 2.093 ;
-use IO::Compress::Gzip 2.093 ;
-use IO::Uncompress::Gunzip 2.093 ;
+use IO::Compress::Base::Common 2.096 ;
+use Compress::Raw::Zlib 2.096 ;
+use IO::Compress::Gzip 2.096 ;
+use IO::Uncompress::Gunzip 2.096 ;
 
 use strict ;
 use warnings ;
 use bytes ;
 our ($VERSION, $XS_VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $XS_VERSION = $VERSION; 
 $VERSION = eval $VERSION;
 
@@ -461,7 +461,7 @@ sub inflate
 
 package Compress::Zlib ;
 
-use IO::Compress::Gzip::Constants 2.093 ;
+use IO::Compress::Gzip::Constants 2.096 ;
 
 sub memGzip($)
 {
@@ -1469,7 +1469,7 @@ of I<Compress::Zlib>.
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1506,7 +1506,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 1995-2019 Paul Marquess. All rights reserved.
+Copyright (c) 1995-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index a8a7762..635091e 100644 (file)
@@ -4,12 +4,12 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 qw(:Status);
+use IO::Compress::Base::Common  2.096 qw(:Status);
 
-use Compress::Raw::Bzip2  2.093 ;
+use Compress::Raw::Bzip2  2.096 ;
 
 our ($VERSION);
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 sub mkCompObject
 {
index 140d29f..4f6f1d6 100644 (file)
@@ -4,13 +4,13 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common 2.093 qw(:Status);
-use Compress::Raw::Zlib  2.093 qw( !crc32 !adler32 ) ;
+use IO::Compress::Base::Common 2.096 qw(:Status);
+use Compress::Raw::Zlib  2.096 qw( !crc32 !adler32 ) ;
                                   
 require Exporter;                                     
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, @EXPORT, %DEFLATE_CONSTANTS);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 @ISA = qw(Exporter);
 @EXPORT_OK = @Compress::Raw::Zlib::DEFLATE_CONSTANTS;
 %EXPORT_TAGS = %Compress::Raw::Zlib::DEFLATE_CONSTANTS;
index 487cfa7..00b529b 100644 (file)
@@ -4,10 +4,10 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 qw(:Status);
+use IO::Compress::Base::Common  2.096 qw(:Status);
 our ($VERSION);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 sub mkCompObject
 {
index f817d13..1f19429 100644 (file)
@@ -6,7 +6,7 @@ require 5.006 ;
 use strict ;
 use warnings;
 
-use IO::Compress::Base::Common 2.093 ;
+use IO::Compress::Base::Common 2.096 ;
 
 use IO::File (); ;
 use Scalar::Util ();
@@ -20,7 +20,7 @@ use Symbol();
 our (@ISA, $VERSION);
 @ISA    = qw(IO::File Exporter);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 #Can't locate object method "SWASHNEW" via package "utf8" (perhaps you forgot to load "utf8"?) at .../ext/Compress-Zlib/Gzip/blib/lib/Compress/Zlib/Common.pm line 16.
 
@@ -1023,7 +1023,7 @@ purpose is to be sub-classed by IO::Compress modules.
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1047,7 +1047,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 87af18b..37501a6 100644 (file)
@@ -11,7 +11,7 @@ use File::GlobMapper;
 require Exporter;
 our ($VERSION, @ISA, @EXPORT, %EXPORT_TAGS, $HAS_ENCODE);
 @ISA = qw(Exporter);
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 @EXPORT = qw( isaFilehandle isaFilename isaScalar
               whatIsInput whatIsOutput
index 13d3b46..950366c 100644 (file)
@@ -5,16 +5,16 @@ use warnings;
 use bytes;
 require Exporter ;
 
-use IO::Compress::Base 2.093 ;
+use IO::Compress::Base 2.096 ;
 
-use IO::Compress::Base::Common  2.093 qw();
-use IO::Compress::Adapter::Bzip2 2.093 ;
+use IO::Compress::Base::Common  2.096 qw();
+use IO::Compress::Adapter::Bzip2 2.096 ;
 
 
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $Bzip2Error);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $Bzip2Error = '';
 
 @ISA    = qw(IO::Compress::Base Exporter);
@@ -51,7 +51,7 @@ sub getExtraParams
 {
     my $self = shift ;
 
-    use IO::Compress::Base::Common  2.093 qw(:Parse);
+    use IO::Compress::Base::Common  2.096 qw(:Parse);
     
     return (  
             'blocksize100k' => [IO::Compress::Base::Common::Parse_unsigned,  1],
@@ -765,7 +765,7 @@ See the L</"Constructor Options"> section for more details.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Compress::Bzip2 at present.
+No symbolic constants are required by IO::Compress::Bzip2 at present.
 
 =over 5
 
@@ -790,7 +790,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -818,7 +818,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 5ecac19..358e019 100644 (file)
@@ -8,16 +8,16 @@ use bytes;
 
 require Exporter ;
 
-use IO::Compress::RawDeflate 2.093 ();
-use IO::Compress::Adapter::Deflate 2.093 ;
+use IO::Compress::RawDeflate 2.096 ();
+use IO::Compress::Adapter::Deflate 2.096 ;
 
-use IO::Compress::Zlib::Constants 2.093 ;
-use IO::Compress::Base::Common  2.093 qw();
+use IO::Compress::Zlib::Constants 2.096 ;
+use IO::Compress::Base::Common  2.096 qw();
 
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, %DEFLATE_CONSTANTS, $DeflateError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $DeflateError = '';
 
 @ISA    = qw(IO::Compress::RawDeflate Exporter);
@@ -914,7 +914,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -951,7 +951,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 697f0f3..d6d11c7 100644 (file)
@@ -658,7 +658,7 @@ file.
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs//issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=>.
 
@@ -682,7 +682,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 3fd1369..68f6008 100644 (file)
@@ -8,12 +8,12 @@ use bytes;
 
 require Exporter ;
 
-use IO::Compress::RawDeflate 2.093 () ; 
-use IO::Compress::Adapter::Deflate 2.093 ;
+use IO::Compress::RawDeflate 2.096 () ; 
+use IO::Compress::Adapter::Deflate 2.096 ;
 
-use IO::Compress::Base::Common  2.093 qw(:Status );
-use IO::Compress::Gzip::Constants 2.093 ;
-use IO::Compress::Zlib::Extra 2.093 ;
+use IO::Compress::Base::Common  2.096 qw(:Status );
+use IO::Compress::Gzip::Constants 2.096 ;
+use IO::Compress::Zlib::Extra 2.096 ;
 
 BEGIN
 {
@@ -25,7 +25,7 @@ BEGIN
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, %DEFLATE_CONSTANTS, $GzipError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $GzipError = '' ;
 
 @ISA    = qw(IO::Compress::RawDeflate Exporter);
@@ -1226,7 +1226,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Copress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Copress>.
 
@@ -1263,7 +1263,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 1d18fc4..c41fa18 100644 (file)
@@ -9,7 +9,7 @@ require Exporter;
 our ($VERSION, @ISA, @EXPORT, %GZIP_OS_Names);
 our ($GZIP_FNAME_INVALID_CHAR_RE, $GZIP_FCOMMENT_INVALID_CHAR_RE);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 @ISA = qw(Exporter);
 
index c833f5e..603c9e0 100644 (file)
@@ -6,15 +6,15 @@ use strict ;
 use warnings;
 use bytes;
 
-use IO::Compress::Base 2.093 ;
-use IO::Compress::Base::Common  2.093 qw(:Status );
-use IO::Compress::Adapter::Deflate 2.093 ;
+use IO::Compress::Base 2.096 ;
+use IO::Compress::Base::Common  2.096 qw(:Status );
+use IO::Compress::Adapter::Deflate 2.096 ;
 
 require Exporter ;
 
 our ($VERSION, @ISA, @EXPORT_OK, %DEFLATE_CONSTANTS, %EXPORT_TAGS, $RawDeflateError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $RawDeflateError = '';
 
 @ISA = qw(IO::Compress::Base Exporter);
@@ -116,8 +116,8 @@ sub getExtraParams
     return getZlibParams();
 }
 
-use IO::Compress::Base::Common  2.093 qw(:Parse);
-use Compress::Raw::Zlib  2.093 qw(Z_DEFLATED Z_DEFAULT_COMPRESSION Z_DEFAULT_STRATEGY);
+use IO::Compress::Base::Common  2.096 qw(:Parse);
+use Compress::Raw::Zlib  2.096 qw(Z_DEFLATED Z_DEFAULT_COMPRESSION Z_DEFAULT_STRATEGY);
 our %PARAMS = (
             #'method'   => [IO::Compress::Base::Common::Parse_unsigned,  Z_DEFLATED],
             'level'     => [IO::Compress::Base::Common::Parse_signed,    Z_DEFAULT_COMPRESSION],
@@ -970,7 +970,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1007,7 +1007,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 70b98b8..63bd998 100644 (file)
@@ -4,30 +4,40 @@ use strict ;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 qw(:Status );
-use IO::Compress::RawDeflate 2.093 ();
-use IO::Compress::Adapter::Deflate 2.093 ;
-use IO::Compress::Adapter::Identity 2.093 ;
-use IO::Compress::Zlib::Extra 2.093 ;
-use IO::Compress::Zip::Constants 2.093 ;
+use IO::Compress::Base::Common  2.096 qw(:Status );
+use IO::Compress::RawDeflate 2.096 ();
+use IO::Compress::Adapter::Deflate 2.096 ;
+use IO::Compress::Adapter::Identity 2.096 ;
+use IO::Compress::Zlib::Extra 2.096 ;
+use IO::Compress::Zip::Constants 2.096 ;
 
 use File::Spec();
 use Config;
 
-use Compress::Raw::Zlib  2.093 (); 
+use Compress::Raw::Zlib  2.096 ();
 
 BEGIN
 {
-    eval { require IO::Compress::Adapter::Bzip2 ; 
-           import  IO::Compress::Adapter::Bzip2 2.093 ; 
-           require IO::Compress::Bzip2 ; 
-           import  IO::Compress::Bzip2 2.093 ; 
+    eval { require IO::Compress::Adapter::Bzip2 ;
+           import  IO::Compress::Adapter::Bzip2 2.096 ;
+           require IO::Compress::Bzip2 ;
+           import  IO::Compress::Bzip2 2.096 ;
          } ;
-         
-    eval { require IO::Compress::Adapter::Lzma ; 
-           import  IO::Compress::Adapter::Lzma 2.093 ; 
-           require IO::Compress::Lzma ; 
-           import  IO::Compress::Lzma 2.093 ; 
+
+    eval { require IO::Compress::Adapter::Lzma ;
+           import  IO::Compress::Adapter::Lzma 2.096 ;
+           require IO::Compress::Lzma ;
+           import  IO::Compress::Lzma 2.096 ;
+         } ;
+    eval { require IO::Compress::Adapter::Xz ;
+           import  IO::Compress::Adapter::Xz 2.096 ;
+           require IO::Compress::Xz ;
+           import  IO::Compress::Xz 2.096 ;
+         } ;
+    eval { require IO::Compress::Adapter::Zstd ;
+           import  IO::Compress::Adapter::Zstd 2.096 ;
+           require IO::Compress::Zstd ;
+           import  IO::Compress::Zstd 2.096 ;
          } ;
 }
 
@@ -36,7 +46,7 @@ require Exporter ;
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, %DEFLATE_CONSTANTS, $ZipError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $ZipError = '';
 
 @ISA = qw(IO::Compress::RawDeflate Exporter);
@@ -45,7 +55,7 @@ $ZipError = '';
 
 push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ;
 
-$EXPORT_TAGS{zip_method} = [qw( ZIP_CM_STORE ZIP_CM_DEFLATE ZIP_CM_BZIP2 ZIP_CM_LZMA)];
+$EXPORT_TAGS{zip_method} = [qw( ZIP_CM_STORE ZIP_CM_DEFLATE ZIP_CM_BZIP2 ZIP_CM_LZMA ZIP_CM_XZ ZIP_CM_ZSTD)];
 push @{ $EXPORT_TAGS{all} }, @{ $EXPORT_TAGS{zip_method} };
 
 Exporter::export_ok_tags('all');
@@ -54,34 +64,42 @@ sub new
 {
     my $class = shift ;
 
-    my $obj = IO::Compress::Base::Common::createSelfTiedObject($class, \$ZipError);    
+    my $obj = IO::Compress::Base::Common::createSelfTiedObject($class, \$ZipError);
     $obj->_create(undef, @_);
 
 }
 
 sub zip
 {
-    my $obj = IO::Compress::Base::Common::createSelfTiedObject(undef, \$ZipError);    
+    my $obj = IO::Compress::Base::Common::createSelfTiedObject(undef, \$ZipError);
     return $obj->_def(@_);
 }
 
 sub isMethodAvailable
 {
     my $method = shift;
-    
+
     # Store & Deflate are always available
     return 1
         if $method == ZIP_CM_STORE || $method == ZIP_CM_DEFLATE ;
-        
-    return 1 
-        if $method == ZIP_CM_BZIP2 and 
+
+    return 1
+        if $method == ZIP_CM_BZIP2 and
            defined $IO::Compress::Adapter::Bzip2::VERSION;
-           
+
     return 1
         if $method == ZIP_CM_LZMA and
            defined $IO::Compress::Adapter::Lzma::VERSION;
-           
-    return 0;       
+
+    return 1
+        if $method == ZIP_CM_XZ and
+           defined $IO::Compress::Adapter::Xz::VERSION;
+
+    return 1
+        if $method == ZIP_CM_ZSTD and
+           defined $IO::Compress::Adapter::ZSTD::VERSION;
+
+    return 0;
 }
 
 sub beforePayload
@@ -94,12 +112,12 @@ sub beforePayload
         my $sparse = *$self->{ZipData}{Sparse} ;
         *$self->{CompSize}->add( $sparse );
         *$self->{UnCompSize}->add( $sparse );
-        
+
         *$self->{FH}->seek($sparse, IO::Handle::SEEK_CUR);
-        
+
         *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32($NULLS, *$self->{ZipData}{CRC32})
             for 1 .. int $sparse / $inc;
-        *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(substr($NULLS, 0,  $sparse % $inc), 
+        *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(substr($NULLS, 0,  $sparse % $inc),
                                          *$self->{ZipData}{CRC32})
             if $sparse % $inc;
     }
@@ -141,6 +159,18 @@ sub mkComp
                                                                                  );
         *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(undef);
     }
+    elsif (*$self->{ZipData}{Method} == ZIP_CM_XZ) {
+        ($obj, $errstr, $errno) = IO::Compress::Adapter::Xz::mkCompObject($got->getValue('preset'),
+                                                                                 $got->getValue('extreme'),
+                                                                                 0
+                                                                                 );
+        *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(undef);
+    }
+    elsif (*$self->{ZipData}{Method} == ZIP_CM_ZSTD) {
+        ($obj, $errstr, $errno) = IO::Compress::Adapter::Zstd::mkCompObject(defined $got->getValue('level') ? $got->getValue('level') : 3,
+                                                                           );
+        *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(undef);
+    }
 
     return $self->saveErrorString(undef, $errstr, $errno)
        if ! defined $obj;
@@ -153,7 +183,7 @@ sub mkComp
     *$self->{ZipData}{AnyZip64} = 0
         if ! defined  *$self->{ZipData}{AnyZip64} ;
 
-    return $obj;    
+    return $obj;
 }
 
 sub reset
@@ -163,7 +193,7 @@ sub reset
     *$self->{Compress}->reset();
     *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32('');
 
-    return STATUS_OK;    
+    return STATUS_OK;
 }
 
 sub filterUncompressed
@@ -187,7 +217,7 @@ sub canonicalName
     # separators become slashes, etc.).
     # Will translate internal slashes in path components (i.e. on Macs) to
     # underscores.  Discards volume names.
-    # When $forceDir is set, returns paths with trailing slashes 
+    # When $forceDir is set, returns paths with trailing slashes
     #
     # input         output
     # .             '.'
@@ -204,8 +234,8 @@ sub canonicalName
 
     my ( $volume, $directories, $file ) =
       File::Spec->splitpath( File::Spec->canonpath($name), $forceDir );
-      
-    my @dirs = map { $_ =~ s{/}{_}g; $_ } 
+
+    my @dirs = map { $_ =~ s{/}{_}g; $_ }
                File::Spec->splitdir($directories);
 
     if ( @dirs > 0 ) { pop (@dirs) if $dirs[-1] eq '' }   # remove empty component
@@ -229,9 +259,9 @@ sub mkHeader
 {
     my $self  = shift;
     my $param = shift ;
-    
+
     *$self->{ZipData}{LocalHdrOffset} = U64::clone(*$self->{ZipData}{Offset});
-        
+
     my $comment = '';
     $comment = $param->valueOrDefault('comment') ;
 
@@ -256,7 +286,7 @@ sub mkHeader
             utf8::downgrade($comment, 1)
                 or Carp::croak "Wide character in zip comment";
         }
-   }   
+   }
 
     my $hdr = '';
 
@@ -267,19 +297,19 @@ sub mkHeader
     my $empty = 0;
     my $osCode = $param->getValue('os_code') ;
     my $extFileAttr = 0 ;
-    
+
     # This code assumes Unix.
     # TODO - revisit this
-    $extFileAttr = 0100644 << 16 
+    $extFileAttr = 0100644 << 16
         if $osCode == ZIP_OS_CODE_UNIX ;
 
     if (*$self->{ZipData}{Zip64}) {
         $empty = IO::Compress::Base::Common::MAX32;
 
         my $x = '';
-        $x .= pack "V V", 0, 0 ; # uncompressedLength   
-        $x .= pack "V V", 0, 0 ; # compressedLength   
-        
+        $x .= pack "V V", 0, 0 ; # uncompressedLength
+        $x .= pack "V V", 0, 0 ; # compressedLength
+
         # Zip64 needs to be first in extra field to workaround a Windows Explorer Bug
         # See http://www.info-zip.org/phpBB3/viewtopic.php?f=3&t=440 for details
         $extra .= IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_ZIP64, $x);
@@ -288,8 +318,8 @@ sub mkHeader
     if (! $param->getValue('minimal')) {
         if ($param->parsed('mtime'))
         {
-            $extra .= mkExtendedTime($param->getValue('mtime'), 
-                                    $param->getValue('atime'), 
+            $extra .= mkExtendedTime($param->getValue('mtime'),
+                                    $param->getValue('atime'),
                                     $param->getValue('ctime'));
 
             $ctlExtra .= mkExtendedTime($param->getValue('mtime'));
@@ -299,30 +329,30 @@ sub mkHeader
         {
             if ( $param->getValue('want_exunixn') )
             {
-                    my $ux3 = mkUnixNExtra( @{ $param->getValue('want_exunixn') }); 
+                    my $ux3 = mkUnixNExtra( @{ $param->getValue('want_exunixn') });
                     $extra    .= $ux3;
                     $ctlExtra .= $ux3;
             }
 
             if ( $param->getValue('exunix2') )
             {
-                    $extra    .= mkUnix2Extra( @{ $param->getValue('exunix2') }); 
+                    $extra    .= mkUnix2Extra( @{ $param->getValue('exunix2') });
                     $ctlExtra .= mkUnix2Extra();
             }
         }
 
-        $extFileAttr = $param->getValue('extattr') 
+        $extFileAttr = $param->getValue('extattr')
             if defined $param->getValue('extattr') ;
 
-        $extra .= $param->getValue('extrafieldlocal') 
+        $extra .= $param->getValue('extrafieldlocal')
             if defined $param->getValue('extrafieldlocal');
 
-        $ctlExtra .= $param->getValue('extrafieldcentral') 
+        $ctlExtra .= $param->getValue('extrafieldcentral')
             if defined $param->getValue('extrafieldcentral');
     }
 
     my $method = *$self->{ZipData}{Method} ;
-    my $gpFlag = 0 ;    
+    my $gpFlag = 0 ;
     $gpFlag |= ZIP_GP_FLAG_STREAMING_MASK
         if *$self->{ZipData}{Stream} ;
 
@@ -356,7 +386,7 @@ sub mkHeader
     $hdr .= pack 'V', $empty     ; # uncompressed length - 0 when streaming
     $hdr .= pack 'v', length $filename ; # filename length
     $hdr .= pack 'v', length $extra ; # extra length
-    
+
     $hdr .= $filename ;
 
     # Remember the offset for the compressed & uncompressed lengths in the
@@ -391,18 +421,18 @@ sub mkHeader
 
     $ctl .= pack 'v', length $ctlExtra ; # extra length
     $ctl .= pack 'v', length $comment ;  # file comment length
-    $ctl .= pack 'v', 0          ; # disk number start 
+    $ctl .= pack 'v', 0          ; # disk number start
     $ctl .= pack 'v', $ifa       ; # internal file attributes
     $ctl .= pack 'V', $extFileAttr   ; # external file attributes
 
     # offset to local hdr
-    if (*$self->{ZipData}{LocalHdrOffset}->is64bit() ) { 
+    if (*$self->{ZipData}{LocalHdrOffset}->is64bit() ) {
         $ctl .= pack 'V', IO::Compress::Base::Common::MAX32 ;
     }
     else {
-        $ctl .= *$self->{ZipData}{LocalHdrOffset}->getPacked_V32() ; 
+        $ctl .= *$self->{ZipData}{LocalHdrOffset}->getPacked_V32() ;
     }
-    
+
     $ctl .= $filename ;
 
     *$self->{ZipData}{Offset}->add32(length $hdr) ;
@@ -424,7 +454,7 @@ sub mkTrailer
         $crc32 = pack "V", *$self->{ZipData}{CRC32};
     }
 
-    my ($ctl, $ctlExtra, $comment) = @{ *$self->{ZipData}{CentralHeader} };   
+    my ($ctl, $ctlExtra, $comment) = @{ *$self->{ZipData}{CentralHeader} };
 
     my $sizes ;
     if (! *$self->{ZipData}{Zip64}) {
@@ -450,7 +480,7 @@ sub mkTrailer
     else {
         $self->writeAt(*$self->{ZipData}{LocalHdrOffset}->get64bit() + 14,  $crc32)
             or return undef;
-        $self->writeAt(*$self->{ZipData}{SizesOffset}, 
+        $self->writeAt(*$self->{ZipData}{SizesOffset},
                 *$self->{ZipData}{Zip64} ? $xtrasize : $sizes)
             or return undef;
     }
@@ -463,31 +493,31 @@ sub mkTrailer
 
     # uncompressed length - only set zip64 if needed
     if (*$self->{UnCompSize}->isAlmost64bit()) { #  || *$self->{ZipData}{Zip64}) {
-        $zip64Payload .= *$self->{UnCompSize}->getPacked_V64() ; 
+        $zip64Payload .= *$self->{UnCompSize}->getPacked_V64() ;
     } else {
         substr($ctl, 24, 4) = *$self->{UnCompSize}->getPacked_V32() ;
     }
 
     # compressed length - only set zip64 if needed
     if (*$self->{CompSize}->isAlmost64bit()) { # || *$self->{ZipData}{Zip64}) {
-        $zip64Payload .= *$self->{CompSize}->getPacked_V64() ; 
+        $zip64Payload .= *$self->{CompSize}->getPacked_V64() ;
     } else {
         substr($ctl, 20, 4) = *$self->{CompSize}->getPacked_V32() ;
     }
 
     # Local Header offset
     $zip64Payload .= *$self->{ZipData}{LocalHdrOffset}->getPacked_V64()
-        if *$self->{ZipData}{LocalHdrOffset}->is64bit() ; 
+        if *$self->{ZipData}{LocalHdrOffset}->is64bit() ;
 
     # disk no - always zero, so don't need to include it.
-    #$zip64Payload .= pack "V", 0    ; 
+    #$zip64Payload .= pack "V", 0    ;
 
     my $zip64Xtra = '';
-    
+
     if (length $zip64Payload) {
         $zip64Xtra = IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_ZIP64, $zip64Payload);
-        
-        substr($ctl, *$self->{ZipData}{ExtraOffset}, 2) = 
+
+        substr($ctl, *$self->{ZipData}{ExtraOffset}, 2) =
              pack 'v', *$self->{ZipData}{ExtraSize} + length $zip64Xtra;
 
         *$self->{ZipData}{AnyZip64} = 1;
@@ -496,7 +526,7 @@ sub mkTrailer
     # Zip64 needs to be first in extra field to workaround a Windows Explorer Bug
     # See http://www.info-zip.org/phpBB3/viewtopic.php?f=3&t=440 for details
     $ctl .= $zip64Xtra . $ctlExtra . $comment;
-    
+
     *$self->{ZipData}{Offset}->add32(length($hdr));
     *$self->{ZipData}{Offset}->add( *$self->{CompSize} );
     push @{ *$self->{ZipData}{CentralDir} }, $ctl ;
@@ -507,17 +537,17 @@ sub mkTrailer
 sub mkFinalTrailer
 {
     my $self = shift ;
-        
+
     my $comment = '';
     $comment = *$self->{ZipData}{ZipComment} ;
 
     my $cd_offset = *$self->{ZipData}{Offset}->get32bit() ; # offset to start central dir
 
     my $entries = @{ *$self->{ZipData}{CentralDir} };
-    
-    *$self->{ZipData}{AnyZip64} = 1 
-        if *$self->{ZipData}{Offset}->is64bit || $entries >= 0xFFFF ;      
-           
+
+    *$self->{ZipData}{AnyZip64} = 1
+        if *$self->{ZipData}{Offset}->is64bit || $entries >= 0xFFFF ;
+
     my $cd = join '', @{ *$self->{ZipData}{CentralDir} };
     my $cd_len = length $cd ;
 
@@ -540,12 +570,12 @@ sub mkFinalTrailer
               .  U64::pack_V64(length $z64e)
               .  $z64e ;
 
-        *$self->{ZipData}{Offset}->add32(length $cd) ; 
+        *$self->{ZipData}{Offset}->add32(length $cd) ;
 
         $z64e .= pack "V", ZIP64_END_CENTRAL_LOC_HDR_SIG; # signature
         $z64e .= pack 'V', 0              ; # number of disk with central dir
         $z64e .= *$self->{ZipData}{Offset}->getPacked_V64() ; # offset to end zip64 central dir
-        $z64e .= pack 'V', 1              ; # Total number of disks 
+        $z64e .= pack 'V', 1              ; # Total number of disks
 
         $cd_offset = IO::Compress::Base::Common::MAX32 ;
         $cd_len = IO::Compress::Base::Common::MAX32 if IO::Compress::Base::Common::isGeMax32 $cd_len ;
@@ -570,7 +600,7 @@ sub ckParams
 {
     my $self = shift ;
     my $got = shift;
-    
+
     $got->setValue('crc32' => 1);
 
     if (! $got->parsed('time') ) {
@@ -581,7 +611,7 @@ sub ckParams
     if ($got->parsed('extime') ) {
         my $timeRef = $got->getValue('extime');
         if ( defined $timeRef) {
-            return $self->saveErrorString(undef, "exTime not a 3-element array ref")   
+            return $self->saveErrorString(undef, "exTime not a 3-element array ref")
                 if ref $timeRef ne 'ARRAY' || @$timeRef != 3;
         }
 
@@ -589,14 +619,14 @@ sub ckParams
         $got->setValue("atime", $timeRef->[0]);
         $got->setValue("ctime", $timeRef->[2]);
     }
-    
+
     # Unix2/3 Extended Attribute
     for my $name (qw(exunix2 exunixn))
     {
         if ($got->parsed($name) ) {
             my $idRef = $got->getValue($name);
             if ( defined $idRef) {
-                return $self->saveErrorString(undef, "$name not a 2-element array ref")   
+                return $self->saveErrorString(undef, "$name not a 2-element array ref")
                     if ref $idRef ne 'ARRAY' || @$idRef != 2;
             }
 
@@ -612,15 +642,15 @@ sub ckParams
     *$self->{ZipData}{Stream} = $got->getValue('stream');
 
     my $method = $got->getValue('method');
-    return $self->saveErrorString(undef, "Unknown Method '$method'")   
+    return $self->saveErrorString(undef, "Unknown Method '$method'")
         if ! defined $ZIP_CM_MIN_VERSIONS{$method};
 
     return $self->saveErrorString(undef, "Bzip2 not available")
-        if $method == ZIP_CM_BZIP2 and 
+        if $method == ZIP_CM_BZIP2 and
            ! defined $IO::Compress::Adapter::Bzip2::VERSION;
 
     return $self->saveErrorString(undef, "Lzma not available")
-        if $method == ZIP_CM_LZMA 
+        if $method == ZIP_CM_LZMA
         and ! defined $IO::Compress::Adapter::Lzma::VERSION;
 
     *$self->{ZipData}{Method} = $method;
@@ -673,11 +703,11 @@ sub outputPayload
 #}
 
 
-our %PARAMS = (            
+our %PARAMS = (
             'stream'    => [IO::Compress::Base::Common::Parse_boolean,   1],
            #'store'     => [IO::Compress::Base::Common::Parse_boolean,   0],
             'method'    => [IO::Compress::Base::Common::Parse_unsigned,  ZIP_CM_DEFLATE],
-            
+
 #            # Zip header fields
             'minimal'   => [IO::Compress::Base::Common::Parse_boolean,   0],
             'zip64'     => [IO::Compress::Base::Common::Parse_boolean,   0],
@@ -689,14 +719,14 @@ our %PARAMS = (
             'efs'       => [IO::Compress::Base::Common::Parse_boolean,   0],
             'time'      => [IO::Compress::Base::Common::Parse_any,       undef],
             'extime'    => [IO::Compress::Base::Common::Parse_any,       undef],
-            'exunix2'   => [IO::Compress::Base::Common::Parse_any,       undef], 
-            'exunixn'   => [IO::Compress::Base::Common::Parse_any,       undef], 
-            'extattr'   => [IO::Compress::Base::Common::Parse_any, 
-                    $Compress::Raw::Zlib::gzip_os_code == 3 
-                        ? 0100644 << 16 
+            'exunix2'   => [IO::Compress::Base::Common::Parse_any,       undef],
+            'exunixn'   => [IO::Compress::Base::Common::Parse_any,       undef],
+            'extattr'   => [IO::Compress::Base::Common::Parse_any,
+                    $Compress::Raw::Zlib::gzip_os_code == 3
+                        ? 0100644 << 16
                         : 0],
             'os_code'   => [IO::Compress::Base::Common::Parse_unsigned,  $Compress::Raw::Zlib::gzip_os_code],
-            
+
             'textflag'  => [IO::Compress::Base::Common::Parse_boolean,   0],
             'extrafieldlocal'  => [IO::Compress::Base::Common::Parse_any,    undef],
             'extrafieldcentral'=> [IO::Compress::Base::Common::Parse_any,    undef],
@@ -705,15 +735,15 @@ our %PARAMS = (
             'preset'   => [IO::Compress::Base::Common::Parse_unsigned, 6],
             'extreme'  => [IO::Compress::Base::Common::Parse_boolean,  0],
 
-            # For internal use only         
+            # For internal use only
             'sparse'    => [IO::Compress::Base::Common::Parse_unsigned,  0],
 
             IO::Compress::RawDeflate::getZlibParams(),
             defined $IO::Compress::Bzip2::VERSION
                 ? IO::Compress::Bzip2::getExtraParams()
                 : ()
-                
-  
+
+
                 );
 
 sub getExtraParams
@@ -744,12 +774,12 @@ sub getFileInfo
     my ($mode, $uid, $gid, $size, $atime, $mtime, $ctime) ;
     if ( $params->parsed('storelinks') )
     {
-        ($mode, $uid, $gid, $size, $atime, $mtime, $ctime) 
+        ($mode, $uid, $gid, $size, $atime, $mtime, $ctime)
                 = (lstat($filename))[2, 4,5,7, 8,9,10] ;
     }
     else
     {
-        ($mode, $uid, $gid, $size, $atime, $mtime, $ctime) 
+        ($mode, $uid, $gid, $size, $atime, $mtime, $ctime)
                 = (stat($filename))[2, 4,5,7, 8,9,10] ;
     }
 
@@ -762,9 +792,9 @@ sub getFileInfo
     $params->setValue('name' => $filename)
         if ! $params->parsed('name') ;
 
-    $params->setValue('time' => $mtime) 
+    $params->setValue('time' => $mtime)
         if ! $params->parsed('time') ;
-    
+
     if ( ! $params->parsed('extime'))
     {
         $params->setValue('mtime' => $mtime) ;
@@ -780,14 +810,14 @@ sub getFileInfo
         my $attr = $mode << 16;
         $attr |= ZIP_A_RONLY if ($mode & S_IWRITE) == 0 ;
         $attr |= ZIP_A_DIR   if ($mode & S_IFMT  ) == S_IFDIR ;
-        
+
         $params->setValue('extattr' => $attr);
     }
 
     $params->setValue('want_exunixn', [$uid, $gid]);
     $params->setValue('uid' => $uid) ;
     $params->setValue('gid' => $gid) ;
-    
+
 }
 
 sub mkExtendedTime
@@ -821,7 +851,7 @@ sub mkUnix2Extra
         $ids .= pack("v", $id);
     }
 
-    return IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_INFO_ZIP_UNIX2, 
+    return IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_INFO_ZIP_UNIX2,
                                                  $ids);
 }
 
@@ -838,7 +868,7 @@ sub mkUnixNExtra
     $ids .= pack "C", $Config{gidsize};
     $ids .= pack "V", $gid;
 
-    return IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_INFO_ZIP_UNIXN, 
+    return IO::Compress::Zlib::Extra::mkSubField(ZIP_EXTRA_ID_INFO_ZIP_UNIXN,
                                                  $ids);
 }
 
@@ -847,8 +877,8 @@ sub mkUnixNExtra
 sub _unixToDosTime    # Archive::Zip::Member
 {
        my $time_t = shift;
-    
-    # TODO - add something to cope with unix time < 1980 
+
+    # TODO - add something to cope with unix time < 1980
        my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime($time_t);
        my $dt = 0;
        $dt += ( $sec >> 1 );
@@ -916,19 +946,35 @@ This module provides a Perl interface that allows writing zip
 compressed data to files or buffer.
 
 The primary purpose of this module is to provide streaming write access to
-zip files and buffers. It is not a general-purpose file archiver. If that
-is what you want, check out C<Archive::Zip> or C<Archive::Zip::SimpleZip>.
-
-At present the following compression methods are supported by IO::Compress::Zip,
-namely Store (no compression at all), Deflate, Bzip2 and LZMA.
+zip files and buffers.
 
-B<Note>
+At present the following compression methods are supported by IO::Compress::Zip
 
 =over 5
 
-=item * To use Bzip2 compression, the module C<IO::Compress::Bzip2> must be installed.
+=item Store (0)
+
+=item Deflate (8)
+
+=item Bzip2 (12)
+
+To write Bzip2 content, the module C<IO::Uncompress::Bunzip2> must
+be installed.
+
+=item Lzma (14)
+
+To write LZMA content, the module C<IO::Uncompress::UnLzma> must
+be installed.
 
-=item * To use LZMA compression, the module C<IO::Compress::Lzma> must be installed.
+=item Zstandard (93)
+
+To write Zstandard content, the module C<IO::Compress::Zstd> must
+be installed.
+
+=item Xz (95)
+
+To write Xz content, the module C<IO::Uncompress::UnXz> must
+be installed.
 
 =back
 
@@ -1338,7 +1384,7 @@ This parameter defaults to 0.
 
 =head3 File Naming Options
 
-A quick bit of zip file terminology -- A zip archive consists of one or more I<archive members>, where each member has an associated 
+A quick bit of zip file terminology -- A zip archive consists of one or more I<archive members>, where each member has an associated
 filename, known as the I<archive member name>.
 
 The options listed in this section control how the I<archive member name> (or filename) is stored the zip archive.
@@ -1355,7 +1401,7 @@ By default when adding a filename to the zip archive, the I<archive member name>
 You should only need to use this option if you want the I<archive member name>
 to be different from the uncompressed filename or when the input is a filehandle or a buffer.
 
-The default behaviour for what I<archive member name> is used when the C<Name> option 
+The default behaviour for what I<archive member name> is used when the C<Name> option
 is I<not> specified depends on the form of the C<$input> parameter:
 
 =over 5
@@ -1365,11 +1411,11 @@ is I<not> specified depends on the form of the C<$input> parameter:
 If the C<$input> parameter is a filename, the
 value of C<$input> will be used for the I<archive member name> .
 
-=item * 
+=item *
 If the C<$input> parameter is not a filename,
 the I<archive member name> will be an empty string.
 
-=back 
+=back
 
 Note that both the C<CanonicalName> and C<FilterName> options
 can modify the value used for the I<archive member name>.
@@ -1484,7 +1530,7 @@ archive.
 
 The default is 0.
 
-=back 
+=back
 
 =head3 Deflate Compression Options
 
@@ -1553,7 +1599,7 @@ The default is 0.
 
 =back
 
-=head3 Lzma Compression Options
+=head3 Lzma and Xz Compression Options
 
 =over 5
 
@@ -1683,11 +1729,11 @@ By default, no comment field is written to the zip file.
 
 =item C<< Method => $method >>
 
-Controls which compression method is used. At present four compression
-methods are supported, namely Store (no compression at all), Deflate,
-Bzip2 and Lzma.
+Controls which compression method is used. At present the compression
+methods are supported are: Store (no compression at all), Deflate,
+Bzip2, Xz and Lzma.
 
-The symbols, ZIP_CM_STORE, ZIP_CM_DEFLATE, ZIP_CM_BZIP2 and ZIP_CM_LZMA
+The symbols, ZIP_CM_STORE, ZIP_CM_DEFLATE, ZIP_CM_BZIP2, ZIP_CM_XZ and ZIP_CM_LZMA
 are used to select the compression method.
 
 These constants are not imported by C<IO::Compress::Zip> by default.
@@ -1704,6 +1750,10 @@ Note that to create Lzma content, the module C<IO::Compress::Lzma> must
 be installed. A fatal error will be thrown if you attempt to create Lzma
 content when C<IO::Compress::Lzma> is not available.
 
+Note that to create Xz content, the module C<IO::Compress::Xz> must
+be installed. A fatal error will be thrown if you attempt to create Xz
+content when C<IO::Compress::Xz> is not available.
+
 The default method is ZIP_CM_DEFLATE.
 
 =item C<< TextFlag => 0|1 >>
@@ -2050,7 +2100,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -2087,7 +2137,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index edae0c2..526e0ba 100644 (file)
@@ -7,7 +7,7 @@ require Exporter;
 
 our ($VERSION, @ISA, @EXPORT, %ZIP_CM_MIN_VERSIONS);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 @ISA = qw(Exporter);
 
@@ -18,7 +18,9 @@ $VERSION = '2.093';
     ZIP_CM_BZIP2
     ZIP_CM_LZMA
     ZIP_CM_PPMD
-    
+    ZIP_CM_XZ
+    ZIP_CM_ZSTD
+
     ZIP_LOCAL_HDR_SIG
     ZIP_DATA_HDR_SIG
     ZIP_CENTRAL_HDR_SIG
@@ -40,7 +42,7 @@ $VERSION = '2.093';
     ZIP_EXTRA_ID_INFO_ZIP_UNIX2
     ZIP_EXTRA_ID_INFO_ZIP_UNIXN
     ZIP_EXTRA_ID_INFO_ZIP_Upath
-    ZIP_EXTRA_ID_INFO_ZIP_Ucom        
+    ZIP_EXTRA_ID_INFO_ZIP_Ucom
     ZIP_EXTRA_ID_JAVA_EXE
 
     ZIP_OS_CODE_UNIX
@@ -55,7 +57,7 @@ $VERSION = '2.093';
     ZIP_A_HIDDEN
     ZIP_A_SYSTEM
     ZIP_A_LABEL
-    ZIP_A_DIR 
+    ZIP_A_DIR
     ZIP_A_ARCHIVE
     );
 
@@ -63,7 +65,9 @@ $VERSION = '2.093';
 use constant ZIP_CM_STORE                      => 0 ;
 use constant ZIP_CM_DEFLATE                    => 8 ;
 use constant ZIP_CM_BZIP2                      => 12 ;
-use constant ZIP_CM_LZMA                       => 14 ; # Not Supported yet
+use constant ZIP_CM_LZMA                       => 14 ;
+use constant ZIP_CM_ZSTD                       => 93 ;
+use constant ZIP_CM_XZ                         => 95 ;
 use constant ZIP_CM_PPMD                       => 98 ; # Not Supported yet
 
 # General Purpose Flag
@@ -116,10 +120,11 @@ use constant ZIP64_MIN_VERSION                 => 45;
             ZIP_CM_BZIP2()                     => 46,
             ZIP_CM_LZMA()                      => 63,
             ZIP_CM_PPMD()                      => 63,
+            ZIP_CM_ZSTD()                      => 20, # Winzip needs these to be 20
+            ZIP_CM_XZ()                        => 20,
             );
 
 
 1;
 
 __END__
-
index c2fecba..a6903a7 100644 (file)
@@ -9,7 +9,7 @@ require Exporter;
 
 our ($VERSION, @ISA, @EXPORT);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 @ISA = qw(Exporter);
 
index 6e13d4f..b5c49b7 100644 (file)
@@ -8,9 +8,9 @@ use bytes;
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
-use IO::Compress::Gzip::Constants 2.093 ;
+use IO::Compress::Gzip::Constants 2.096 ;
 
 sub ExtraFieldError
 {
index 3fc176e..60b34ba 100644 (file)
@@ -4,12 +4,12 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common 2.093 qw(:Status);
+use IO::Compress::Base::Common 2.096 qw(:Status);
 
-use Compress::Raw::Bzip2 2.093 ;
+use Compress::Raw::Bzip2 2.096 ;
 
 our ($VERSION, @ISA);
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 sub mkUncompObject
 {
index c8622a5..84d74c9 100644 (file)
@@ -4,14 +4,14 @@ use warnings;
 use strict;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 qw(:Status);
+use IO::Compress::Base::Common  2.096 qw(:Status);
 use IO::Compress::Zip::Constants ;
 
 our ($VERSION);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
-use Compress::Raw::Zlib  2.093 ();
+use Compress::Raw::Zlib  2.096 ();
 
 sub mkUncompObject
 {
index a27af5b..63e8707 100644 (file)
@@ -4,11 +4,11 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 qw(:Status);
-use Compress::Raw::Zlib  2.093 qw(Z_OK Z_BUF_ERROR Z_STREAM_END Z_FINISH MAX_WBITS);
+use IO::Compress::Base::Common  2.096 qw(:Status);
+use Compress::Raw::Zlib  2.096 qw(Z_OK Z_BUF_ERROR Z_STREAM_END Z_FINISH MAX_WBITS);
 
 our ($VERSION);
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 
 
index 6172737..63ada56 100644 (file)
@@ -6,22 +6,22 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 ();
+use IO::Compress::Base::Common  2.096 ();
 
-use IO::Uncompress::Adapter::Inflate  2.093 ();
+use IO::Uncompress::Adapter::Inflate  2.096 ();
 
 
-use IO::Uncompress::Base  2.093 ;
-use IO::Uncompress::Gunzip  2.093 ;
-use IO::Uncompress::Inflate  2.093 ;
-use IO::Uncompress::RawInflate  2.093 ;
-use IO::Uncompress::Unzip  2.093 ;
+use IO::Uncompress::Base  2.096 ;
+use IO::Uncompress::Gunzip  2.096 ;
+use IO::Uncompress::Inflate  2.096 ;
+use IO::Uncompress::RawInflate  2.096 ;
+use IO::Uncompress::Unzip  2.096 ;
 
 require Exporter ;
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $AnyInflateError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $AnyInflateError = '';
 
 @ISA = qw(IO::Uncompress::Base Exporter);
@@ -48,7 +48,7 @@ sub anyinflate
 
 sub getExtraParams
 {
-    use IO::Compress::Base::Common  2.093 qw(:Parse);
+    use IO::Compress::Base::Common  2.096 qw(:Parse);
     return ( 'rawinflate' => [Parse_boolean,  0] ) ;
 }
 
@@ -941,7 +941,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::AnyInflate at present.
+No symbolic constants are required by IO::Uncompress::AnyInflate at present.
 
 =over 5
 
@@ -962,7 +962,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -999,7 +999,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 251b7cf..ae8acdf 100644 (file)
@@ -4,16 +4,16 @@ use strict;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common 2.093 ();
+use IO::Compress::Base::Common 2.096 ();
 
-use IO::Uncompress::Base 2.093 ;
+use IO::Uncompress::Base 2.096 ;
 
 
 require Exporter ;
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $AnyUncompressError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $AnyUncompressError = '';
 
 @ISA = qw(IO::Uncompress::Base Exporter);
@@ -33,26 +33,26 @@ BEGIN
    # Don't trigger any __DIE__ Hooks.
    local $SIG{__DIE__};
 
-   eval ' use IO::Uncompress::Adapter::Inflate 2.093 ;';
-   eval ' use IO::Uncompress::Adapter::Bunzip2 2.093 ;';
-   eval ' use IO::Uncompress::Adapter::LZO 2.093 ;';
-   eval ' use IO::Uncompress::Adapter::Lzf 2.093 ;';
-   eval ' use IO::Uncompress::Adapter::UnLzma 2.093 ;';
-   eval ' use IO::Uncompress::Adapter::UnXz 2.093 ;';
-   eval ' use IO::Uncompress::Adapter::UnZstd 2.083 ;';
-   eval ' use IO::Uncompress::Adapter::UnLzip 2.093 ;';
-
-   eval ' use IO::Uncompress::Bunzip2 2.093 ;';
-   eval ' use IO::Uncompress::UnLzop 2.093 ;';
-   eval ' use IO::Uncompress::Gunzip 2.093 ;';
-   eval ' use IO::Uncompress::Inflate 2.093 ;';
-   eval ' use IO::Uncompress::RawInflate 2.093 ;';
-   eval ' use IO::Uncompress::Unzip 2.093 ;';
-   eval ' use IO::Uncompress::UnLzf 2.093 ;';
-   eval ' use IO::Uncompress::UnLzma 2.093 ;';
-   eval ' use IO::Uncompress::UnXz 2.093 ;';
-   eval ' use IO::Uncompress::UnZstd 2.093 ;';
-   eval ' use IO::Uncompress::UnLzip 2.093 ;';
+   eval ' use IO::Uncompress::Adapter::Inflate 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::Bunzip2 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::LZO 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::Lzf 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::UnLzma 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::UnXz 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::UnZstd 2.096 ;';
+   eval ' use IO::Uncompress::Adapter::UnLzip 2.096 ;';
+
+   eval ' use IO::Uncompress::Bunzip2 2.096 ;';
+   eval ' use IO::Uncompress::UnLzop 2.096 ;';
+   eval ' use IO::Uncompress::Gunzip 2.096 ;';
+   eval ' use IO::Uncompress::Inflate 2.096 ;';
+   eval ' use IO::Uncompress::RawInflate 2.096 ;';
+   eval ' use IO::Uncompress::Unzip 2.096 ;';
+   eval ' use IO::Uncompress::UnLzf 2.096 ;';
+   eval ' use IO::Uncompress::UnLzma 2.096 ;';
+   eval ' use IO::Uncompress::UnXz 2.096 ;';
+   eval ' use IO::Uncompress::UnZstd 2.096 ;';
+   eval ' use IO::Uncompress::UnLzip 2.096 ;';
 
 }
 
@@ -70,7 +70,7 @@ sub anyuncompress
 }
 
 sub getExtraParams
-{ 
+{
     return ( 'rawinflate' => [IO::Compress::Base::Common::Parse_boolean,  0] ,
              'unlzma'     => [IO::Compress::Base::Common::Parse_boolean,  0] ) ;
 }
@@ -103,13 +103,13 @@ sub mkUncomp
             if ! defined $obj;
 
         *$self->{Uncomp} = $obj;
-        
+
         my @possible = qw( Inflate Gunzip Unzip );
-        unshift @possible, 'RawInflate' 
+        unshift @possible, 'RawInflate'
             if $got->getValue('rawinflate');
 
         $magic = $self->ckMagic( @possible );
-        
+
         if ($magic) {
             *$self->{Info} = $self->readHeader($magic)
                 or return undef ;
@@ -126,9 +126,9 @@ sub mkUncomp
             if ! defined $obj;
 
         *$self->{Uncomp} = $obj;
-        
+
         my @possible = qw( UnLzma );
-        #unshift @possible, 'RawInflate' 
+        #unshift @possible, 'RawInflate'
         #    if $got->getValue('rawinflate');
 
         if ( *$self->{Info} = $self->ckMagic( @possible ))
@@ -206,7 +206,7 @@ sub mkUncomp
         *$self->{Info} = $self->readHeader($magic)
             or return undef ;
 
-        my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::Zstd::mkUncompObject();
+        my ($obj, $errstr, $errno) = IO::Uncompress::Adapter::UnZstd::mkUncompObject();
 
         return $self->saveErrorString(undef, $errstr, $errno)
             if ! defined $obj;
@@ -257,7 +257,7 @@ sub ckMagic
 
         $self->pushBack(*$self->{HeaderPending})  ;
         *$self->{HeaderPending} = ''  ;
-    }    
+    }
 
     bless $self => $keep;
     return undef;
@@ -270,7 +270,7 @@ __END__
 
 =head1 NAME
 
-IO::Uncompress::AnyUncompress - Uncompress gzip, zip, bzip2, xz, lzma, lzip, lzf or lzop file/buffer
+IO::Uncompress::AnyUncompress - Uncompress gzip, zip, bzip2, zstd, xz, lzma, lzip, lzf or lzop file/buffer
 
 =head1 SYNOPSIS
 
@@ -333,6 +333,8 @@ The formats supported are:
 
 =item zip
 
+=item zstd (Zstandard)
+
 =item bzip2
 
 =item lzop
@@ -1034,7 +1036,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::AnyUncompress at present.
+No symbolic constants are required by IO::Uncompress::AnyUncompress at present.
 
 =over 5
 
@@ -1051,7 +1053,7 @@ Same as doing this
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1075,7 +1077,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index b9901ca..91a50e7 100644 (file)
@@ -9,12 +9,12 @@ our (@ISA, $VERSION, @EXPORT_OK, %EXPORT_TAGS);
 @ISA    = qw(IO::File Exporter);
 
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 use constant G_EOF => 0 ;
 use constant G_ERR => -1 ;
 
-use IO::Compress::Base::Common 2.093 ;
+use IO::Compress::Base::Common 2.096 ;
 
 use IO::File ;
 use Symbol;
@@ -1536,7 +1536,7 @@ purpose is to be sub-classed by IO::Uncompress modules.
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1560,7 +1560,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 8e805d4..65932c1 100644 (file)
@@ -4,15 +4,15 @@ use strict ;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common 2.093 qw(:Status );
+use IO::Compress::Base::Common 2.096 qw(:Status );
 
-use IO::Uncompress::Base 2.093 ;
-use IO::Uncompress::Adapter::Bunzip2 2.093 ;
+use IO::Uncompress::Base 2.096 ;
+use IO::Uncompress::Adapter::Bunzip2 2.096 ;
 
 require Exporter ;
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $Bunzip2Error);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $Bunzip2Error = '';
 
 @ISA    = qw(IO::Uncompress::Base Exporter);
@@ -858,7 +858,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::Bunzip2 at present.
+No symbolic constants are required by IO::Uncompress::Bunzip2 at present.
 
 =over 5
 
@@ -879,7 +879,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -907,7 +907,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 6e57e96..2bb383c 100644 (file)
@@ -9,12 +9,12 @@ use strict ;
 use warnings;
 use bytes;
 
-use IO::Uncompress::RawInflate 2.093 ;
+use IO::Uncompress::RawInflate 2.096 ;
 
-use Compress::Raw::Zlib 2.093 () ;
-use IO::Compress::Base::Common 2.093 qw(:Status );
-use IO::Compress::Gzip::Constants 2.093 ;
-use IO::Compress::Zlib::Extra 2.093 ;
+use Compress::Raw::Zlib 2.096 () ;
+use IO::Compress::Base::Common 2.096 qw(:Status );
+use IO::Compress::Gzip::Constants 2.096 ;
+use IO::Compress::Zlib::Extra 2.096 ;
 
 require Exporter ;
 
@@ -28,7 +28,7 @@ Exporter::export_ok_tags('all');
 
 $GunzipError = '';
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 
 sub new
 {
@@ -1064,7 +1064,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::Gunzip at present.
+No symbolic constants are required by IO::Uncompress::Gunzip at present.
 
 =over 5
 
@@ -1085,7 +1085,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1122,7 +1122,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 993a1dd..3d576f9 100644 (file)
@@ -5,15 +5,15 @@ use strict ;
 use warnings;
 use bytes;
 
-use IO::Compress::Base::Common  2.093 qw(:Status );
-use IO::Compress::Zlib::Constants 2.093 ;
+use IO::Compress::Base::Common  2.096 qw(:Status );
+use IO::Compress::Zlib::Constants 2.096 ;
 
-use IO::Uncompress::RawInflate  2.093 ;
+use IO::Uncompress::RawInflate  2.096 ;
 
 require Exporter ;
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $InflateError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $InflateError = '';
 
 @ISA    = qw(IO::Uncompress::RawInflate Exporter);
@@ -936,7 +936,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::Inflate at present.
+No symbolic constants are required by IO::Uncompress::Inflate at present.
 
 =over 5
 
@@ -957,7 +957,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -994,7 +994,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 2fa3188..b5a4b8a 100644 (file)
@@ -5,16 +5,16 @@ use strict ;
 use warnings;
 use bytes;
 
-use Compress::Raw::Zlib  2.093 ;
-use IO::Compress::Base::Common  2.093 qw(:Status );
+use Compress::Raw::Zlib  2.096 ;
+use IO::Compress::Base::Common  2.096 qw(:Status );
 
-use IO::Uncompress::Base  2.093 ;
-use IO::Uncompress::Adapter::Inflate  2.093 ;
+use IO::Uncompress::Base  2.096 ;
+use IO::Uncompress::Adapter::Inflate  2.096 ;
 
 require Exporter ;
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, %DEFLATE_CONSTANTS, $RawInflateError);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $RawInflateError = '';
 
 @ISA    = qw(IO::Uncompress::Base Exporter);
@@ -1064,7 +1064,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::RawInflate at present.
+No symbolic constants are required by IO::Uncompress::RawInflate at present.
 
 =over 5
 
@@ -1085,7 +1085,7 @@ See L<IO::Compress::FAQ|IO::Compress::FAQ/"Compressed files and Net::FTP">
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1122,7 +1122,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 856487f..24cd66e 100644 (file)
@@ -9,24 +9,28 @@ use warnings;
 use bytes;
 
 use IO::File;
-use IO::Uncompress::RawInflate  2.093 ;
-use IO::Compress::Base::Common  2.093 qw(:Status );
-use IO::Uncompress::Adapter::Inflate  2.093 ;
-use IO::Uncompress::Adapter::Identity 2.093 ;
-use IO::Compress::Zlib::Extra 2.093 ;
-use IO::Compress::Zip::Constants 2.093 ;
+use IO::Uncompress::RawInflate  2.096 ;
+use IO::Compress::Base::Common  2.096 qw(:Status );
+use IO::Uncompress::Adapter::Inflate  2.096 ;
+use IO::Uncompress::Adapter::Identity 2.096 ;
+use IO::Compress::Zlib::Extra 2.096 ;
+use IO::Compress::Zip::Constants 2.096 ;
 
-use Compress::Raw::Zlib  2.093 () ;
+use Compress::Raw::Zlib  2.096 () ;
 
 BEGIN
 {
    # Don't trigger any __DIE__ Hooks.
    local $SIG{__DIE__};
-       
+
     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::UnXz ;
+          import  IO::Uncompress::Adapter::UnXz } ;
+    eval{ require IO::Uncompress::Adapter::UnZstd ;
+          import  IO::Uncompress::Adapter::UnZstd } ;
 }
 
 
@@ -34,7 +38,7 @@ require Exporter ;
 
 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $UnzipError, %headerLookup);
 
-$VERSION = '2.093';
+$VERSION = '2.096';
 $UnzipError = '';
 
 @ISA    = qw(IO::Uncompress::RawInflate Exporter);
@@ -52,6 +56,15 @@ Exporter::export_ok_tags('all');
         ZIP64_DIGITAL_SIGNATURE_SIG,    \&skipDigitalSignature,
         );
 
+my %MethodNames = (
+        ZIP_CM_DEFLATE()    => 'Deflated',
+        ZIP_CM_BZIP2()      => 'Bzip2',
+        ZIP_CM_LZMA()       => 'Lzma',
+        ZIP_CM_STORE()      => 'Stored',
+        ZIP_CM_XZ()         => 'Xz',
+        ZIP_CM_ZSTD()       => 'Zstd',
+    );
+
 sub new
 {
     my $class = shift ;
@@ -67,18 +80,18 @@ sub unzip
 
 sub getExtraParams
 {
-   
+
     return (
 #            # Zip header fields
             'name'    => [IO::Compress::Base::Common::Parse_any,       undef],
 
             'stream'  => [IO::Compress::Base::Common::Parse_boolean,   0],
             'efs'     => [IO::Compress::Base::Common::Parse_boolean,   0],
-            
+
             # TODO - This means reading the central directory to get
             # 1. the local header offsets
             # 2. The compressed data length
-        );    
+        );
 }
 
 sub ckParams
@@ -119,9 +132,9 @@ sub ckMagic
 
     *$self->{HeaderPending} = $magic ;
 
-    return $self->HeaderError("Minimum header size is " . 
-                              4 . " bytes") 
-        if length $magic != 4 ;                                    
+    return $self->HeaderError("Minimum header size is " .
+                              4 . " bytes")
+        if length $magic != 4 ;
 
     return $self->HeaderError("Bad Magic")
         if ! _isZipMagic($magic) ;
@@ -189,9 +202,9 @@ sub readHeader
 
                 $status = *$self->{Uncomp}->uncompr(\$b, \$temp_buf, 0, $out);
 
-                return $self->saveErrorString(undef, *$self->{Uncomp}{Error}, 
+                return $self->saveErrorString(undef, *$self->{Uncomp}{Error},
                                                      *$self->{Uncomp}{ErrorNo})
-                    if $self->saveStatus($status) == STATUS_ERROR;                
+                    if $self->saveStatus($status) == STATUS_ERROR;
 
                 $self->pushBack($b)  ;
 
@@ -248,7 +261,7 @@ sub chkTrailer
             if $sig != ZIP_DATA_HDR_SIG;
     }
     else {
-        ($CRC32, $cSize, $uSize) = 
+        ($CRC32, $cSize, $uSize) =
             (*$self->{ZipData}{Crc32},
              *$self->{ZipData}{CompressedLen},
              *$self->{ZipData}{UnCompressedLen});
@@ -334,7 +347,7 @@ sub skipCentralDirectory
 
     my $buffer;
     $self->smartReadExact(\$buffer, 46 - 4)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      46 . " bytes") ;
 
     my $keep = $magic . $buffer ;
@@ -348,7 +361,7 @@ sub skipCentralDirectory
    #my $crc32              = unpack ("V", substr($buffer, 16-4, 4));
     my $compressedLength   = unpack ("V", substr($buffer, 20-4, 4));
     my $uncompressedLength = unpack ("V", substr($buffer, 24-4, 4));
-    my $filename_length    = unpack ("v", substr($buffer, 28-4, 2)); 
+    my $filename_length    = unpack ("v", substr($buffer, 28-4, 2));
     my $extra_length       = unpack ("v", substr($buffer, 30-4, 2));
     my $comment_length     = unpack ("v", substr($buffer, 32-4, 2));
    #my $disk_start         = unpack ("v", substr($buffer, 34-4, 2));
@@ -356,7 +369,7 @@ sub skipCentralDirectory
    #my $ext_file_attrib    = unpack ("V", substr($buffer, 38-4, 2));
    #my $lcl_hdr_offset     = unpack ("V", substr($buffer, 42-4, 2));
 
-    
+
     my $filename;
     my $extraField;
     my $comment ;
@@ -391,7 +404,7 @@ sub skipArchiveExtra
 
     my $buffer;
     $self->smartReadExact(\$buffer, 4)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      4 . " bytes") ;
 
     my $keep = $magic . $buffer ;
@@ -399,7 +412,7 @@ sub skipArchiveExtra
     my $size = unpack ("V", $buffer);
 
     $self->smartReadExact(\$buffer, $size)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      $size . " bytes") ;
 
     $keep .= $buffer ;
@@ -416,7 +429,7 @@ sub skipCentralDirectory64Rec
 
     my $buffer;
     $self->smartReadExact(\$buffer, 8)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      8 . " bytes") ;
 
     my $keep = $magic . $buffer ;
@@ -425,7 +438,7 @@ sub skipCentralDirectory64Rec
     my $size = $sizeHi * U64::MAX32 + $sizeLo;
 
     $self->fastForward($size)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      $size . " bytes") ;
 
    #$keep .= $buffer ;
@@ -450,7 +463,7 @@ sub skipCentralDirectory64Loc
 
     my $buffer;
     $self->smartReadExact(\$buffer, 20 - 4)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      20 . " bytes") ;
 
     my $keep = $magic . $buffer ;
@@ -471,7 +484,7 @@ sub skipEndCentralDirectory
 
     my $buffer;
     $self->smartReadExact(\$buffer, 22 - 4)
-        or return $self->TrailerError("Minimum header size is " . 
+        or return $self->TrailerError("Minimum header size is " .
                                      22 . " bytes") ;
 
     my $keep = $magic . $buffer ;
@@ -485,7 +498,7 @@ sub skipEndCentralDirectory
    #my $offsetToCD         = unpack ("V", substr($buffer, 16-4, 4));
     my $comment_length     = unpack ("v", substr($buffer, 20-4, 2));
 
-    
+
     my $comment ;
     if ($comment_length)
     {
@@ -516,9 +529,9 @@ sub _readFullZipHeader($)
 
     *$self->{HeaderPending} = $magic ;
 
-    return $self->HeaderError("Minimum header size is " . 
-                              30 . " bytes") 
-        if length $magic != 4 ;                                    
+    return $self->HeaderError("Minimum header size is " .
+                              30 . " bytes")
+        if length $magic != 4 ;
 
 
     return $self->HeaderError("Bad Magic")
@@ -536,7 +549,7 @@ sub _readZipHeader($)
     my ($buffer) = '' ;
 
     $self->smartReadExact(\$buffer, 30 - 4)
-        or return $self->HeaderError("Minimum header size is " . 
+        or return $self->HeaderError("Minimum header size is " .
                                      30 . " bytes") ;
 
     my $keep = $magic . $buffer ;
@@ -549,13 +562,19 @@ sub _readZipHeader($)
     my $crc32              = unpack ("V", substr($buffer, 14-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 $filename_length    = unpack ("v", substr($buffer, 26-4, 2));
     my $extra_length       = unpack ("v", substr($buffer, 28-4, 2));
 
     my $filename;
     my $extraField;
     my @EXTRA = ();
-    my $streamingMode = ($gpFlag & ZIP_GP_FLAG_STREAMING_MASK) ? 1 : 0 ;
+
+    # Some programs (some versions of LibreOffice) mark entries as streamed, but still fill out
+    # compressedLength/uncompressedLength & crc32 in the local file header.
+    # The expected data descriptor is not populated.
+    # So only assume streaming if the Streaming bit is set AND the compressed length is zero
+    my $streamingMode = (($gpFlag & ZIP_GP_FLAG_STREAMING_MASK)  && $crc32 == 0) ? 1 : 0 ;
+
     my $efs_flag = ($gpFlag & ZIP_GP_FLAG_LANGUAGE_ENCODING) ? 1 : 0;
 
     return $self->HeaderError("Encrypted content not supported")
@@ -577,7 +596,7 @@ sub _readZipHeader($)
             require Encode;
             eval { $filename = Encode::decode_utf8($filename, 1) }
                 or Carp::croak "Zip Filename not UTF-8" ;
-        }     
+        }
 
         $keep .= $filename ;
     }
@@ -601,7 +620,7 @@ sub _readZipHeader($)
         {
             $Extra{$_->[0]} = \$_->[1];
         }
-        
+
         if (defined $Extra{ZIP_EXTRA_ID_ZIP64()})
         {
             $zip64 = 1 ;
@@ -616,7 +635,7 @@ sub _readZipHeader($)
                 my $offset = 0 ;
 
                 if (U64::full32 $uncompressedLength->get32bit() ) {
-                    $uncompressedLength 
+                    $uncompressedLength
                             = U64::newUnpack_V64 substr($buff, 0, 8);
 
                     $offset += 8 ;
@@ -624,7 +643,7 @@ sub _readZipHeader($)
 
                 if (U64::full32 $compressedLength->get32bit() ) {
 
-                    $compressedLength 
+                    $compressedLength
                         = U64::newUnpack_V64 substr($buff, $offset, 8);
 
                     $offset += 8 ;
@@ -657,18 +676,40 @@ sub _readZipHeader($)
     {
         return $self->HeaderError("Unsupported Compression format $compressedMethod")
             if ! defined $IO::Uncompress::Adapter::Bunzip2::VERSION ;
-        
+
         *$self->{Type} = 'zip-bzip2';
-        
+
         my $obj = IO::Uncompress::Adapter::Bunzip2::mkUncompObject();
 
         *$self->{Uncomp} = $obj;
     }
+    elsif ($compressedMethod == ZIP_CM_XZ)
+    {
+        return $self->HeaderError("Unsupported Compression format $compressedMethod")
+            if ! defined $IO::Uncompress::Adapter::UnXz::VERSION ;
+
+        *$self->{Type} = 'zip-xz';
+
+        my $obj = IO::Uncompress::Adapter::UnXz::mkUncompObject();
+
+        *$self->{Uncomp} = $obj;
+    }
+    elsif ($compressedMethod == ZIP_CM_ZSTD)
+    {
+        return $self->HeaderError("Unsupported Compression format $compressedMethod")
+            if ! defined $IO::Uncompress::Adapter::UnZstd::VERSION ;
+
+        *$self->{Type} = 'zip-zstd';
+
+        my $obj = IO::Uncompress::Adapter::UnZstd::mkUncompObject();
+
+        *$self->{Uncomp} = $obj;
+    }
     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)
@@ -695,7 +736,7 @@ sub _readZipHeader($)
     elsif ($compressedMethod == ZIP_CM_STORE)
     {
         *$self->{Type} = 'zip-stored';
-        
+
         my $obj =
         IO::Uncompress::Adapter::Identity::mkUncompObject($streamingMode,
                                                           $zip64);
@@ -724,15 +765,7 @@ sub _readZipHeader($)
         'Stream'             => $streamingMode,
 
         'MethodID'           => $compressedMethod,
-        'MethodName'         => $compressedMethod == ZIP_CM_DEFLATE 
-                                 ? "Deflated" 
-                                 : $compressedMethod == ZIP_CM_BZIP2
-                                     ? "Bzip2"
-                                     : $compressedMethod == ZIP_CM_LZMA
-                                         ? "Lzma"
-                                         : $compressedMethod == ZIP_CM_STORE
-                                             ? "Stored"
-                                             : "Unknown" ,
+        'MethodName'         => $MethodNames{$compressedMethod} || 'Unknown',
 
 #        'TextFlag'      => $flag & GZIP_FLG_FTEXT ? 1 : 0,
 #        'HeaderCRCFlag' => $flag & GZIP_FLG_FHCRC ? 1 : 0,
@@ -741,7 +774,7 @@ sub _readZipHeader($)
 #        'ExtraFlag'     => $flag & GZIP_FLG_FEXTRA ? 1 : 0,
 #        'Comment'       => $comment,
 #        'OsID'          => $os,
-#        'OsName'        => defined $GZIP_OS_Names{$os} 
+#        'OsName'        => defined $GZIP_OS_Names{$os}
 #                                 ? $GZIP_OS_Names{$os} : "Unknown",
 #        'HeaderCRC'     => $HeaderCRC,
 #        'Flags'         => $flag,
@@ -763,7 +796,7 @@ sub filterUncompressed
     else {
         *$self->{ZipData}{CRC32} = Compress::Raw::Zlib::crc32(${$_[0]}, *$self->{ZipData}{CRC32}, $_[1]);
     }
-}    
+}
 
 
 # from Archive::Zip & info-zip
@@ -805,7 +838,7 @@ sub _dosToUnixTime
 #
 #    # Now walk the Central Directory Records
 #    my $buffer ;
-#    while ($self->smartReadExact(\$buffer, 46) && 
+#    while ($self->smartReadExact(\$buffer, 46) &&
 #           unpack("V", $buffer) == ZIP_CENTRAL_HDR_SIG) {
 #
 #        my $compressedLength   = unpack ("V", substr($buffer, 20, 4));
@@ -813,7 +846,7 @@ sub _dosToUnixTime
 #        my $extra_length       = unpack ("v", substr($buffer, 30, 2));
 #        my $comment_length     = unpack ("v", substr($buffer, 32, 2));
 #
-#        $self->smarkSeek($filename_length + $extra_length + $comment_length, 0, SEEK_CUR) 
+#        $self->smarkSeek($filename_length + $extra_length + $comment_length, 0, SEEK_CUR)
 #            if $extra_length || $comment_length || $filename_length;
 #        push @CD, $compressedLength ;
 #    }
@@ -833,7 +866,7 @@ sub _dosToUnixTime
 #    my $buffer;
 #    $self->smartReadExact(\$buffer, 22) ;
 #
-#    my $zip64 = 0;                             
+#    my $zip64 = 0;
 #    my $centralDirOffset ;
 #    if ( unpack("V", $buffer) == ZIP_END_CENTRAL_HDR_SIG ) {
 #        $centralDirOffset = unpack ("V", substr($buffer, 16, 2));
@@ -864,7 +897,7 @@ sub skip
     else {
         $self->smartSeek($size, SEEK_CUR);
     }
-    
+
 }
 
 
@@ -888,7 +921,7 @@ sub scanCentralDirectory
 
     # Now walk the Central Directory Records
     my $buffer ;
-    while ($self->smartReadExact(\$buffer, 46) && 
+    while ($self->smartReadExact(\$buffer, 46) &&
            unpack("V", $buffer) == ZIP_CENTRAL_HDR_SIG) {
 
         my $compressedLength   = unpack("V", substr($buffer, 20, 4));
@@ -903,7 +936,7 @@ sub scanCentralDirectory
 
         if (U64::full32 $compressedLength ) {
             $self->smartReadExact(\$buffer, $extra_length) ;
-            die "xxx $offset $comment_length $filename_length $extra_length" . length($buffer) 
+            die "xxx $offset $comment_length $filename_length $extra_length" . length($buffer)
                 if length($buffer) != $extra_length;
             my $got = $self->get64Extra($buffer, U64::full32 $uncompressedLength);
 
@@ -915,7 +948,7 @@ sub scanCentralDirectory
         }
 
         $self->skip($comment_length ) ;
-            
+
         push @CD, $v64 ;
     }
 
@@ -932,7 +965,7 @@ sub get64Extra
     my $is_uncomp = shift ;
 
     my $extra = IO::Compress::Zlib::Extra::findID(0x0001, $buffer);
-                                            
+
     if (! defined $extra)
     {
         return undef;
@@ -941,7 +974,7 @@ sub get64Extra
     {
         my $u64 = U64::newUnpack_V64(substr($extra,  $is_uncomp ? 8 : 0)) ;
         return $u64;
-    }    
+    }
 }
 
 sub offsetFromZip64
@@ -949,20 +982,20 @@ sub offsetFromZip64
     my $self = shift ;
     my $here = shift;
 
-    $self->smartSeek($here - 20, 0, SEEK_SET) 
+    $self->smartSeek($here - 20, 0, SEEK_SET)
         or die "xx $!" ;
 
     my $buffer;
     my $got = 0;
-    $self->smartReadExact(\$buffer, 20)  
+    $self->smartReadExact(\$buffer, 20)
         or die "xxx $here $got $!" ;
 
     if ( unpack("V", $buffer) == ZIP64_END_CENTRAL_LOC_HDR_SIG ) {
         my $cd64 = U64::Value_VV64 substr($buffer,  8, 8);
-       
+
         $self->smartSeek($cd64, 0, SEEK_SET) ;
 
-        $self->smartReadExact(\$buffer, 4) 
+        $self->smartReadExact(\$buffer, 4)
             or die "xxx" ;
 
         if ( unpack("V", $buffer) == ZIP64_END_CENTRAL_REC_HDR_SIG ) {
@@ -977,7 +1010,7 @@ sub offsetFromZip64
 
             return $cd64 ;
         }
-        
+
         die "zzz";
     }
 
@@ -998,10 +1031,10 @@ sub findCentralDirectoryOffset
     my $here = $self->tell();
 
     my $buffer;
-    $self->smartReadExact(\$buffer, 22) 
+    $self->smartReadExact(\$buffer, 22)
         or die "xxx" ;
 
-    my $zip64 = 0;                             
+    my $zip64 = 0;
     my $centralDirOffset ;
     if ( unpack("V", $buffer) == ZIP_END_CENTRAL_HDR_SIG ) {
         $centralDirOffset = unpack("V", substr($buffer, 16,  4));
@@ -1019,7 +1052,7 @@ sub findCentralDirectoryOffset
                 $seekTo = 0;
                 $want = $fileLen ;
             }
-            $self->smartSeek( $seekTo, 0, SEEK_SET) 
+            $self->smartSeek( $seekTo, 0, SEEK_SET)
                 or die "xxx $!" ;
             my $got;
             $self->smartReadExact($buffer, $want)
@@ -1105,6 +1138,39 @@ zlib files/buffers.
 
 For writing zip files/buffers, see the companion module IO::Compress::Zip.
 
+The primary purpose of this module is to provide I<streaming> read access to
+zip files and buffers.
+
+At present the following compression methods are supported by IO::Uncompress::Unzip
+
+=over 5
+
+=item Store (0)
+
+=item Deflate (8)
+
+=item Bzip2 (12)
+
+To read Bzip2 content, the module C<IO::Uncompress::Bunzip2> must
+be installed.
+
+=item Lzma (14)
+
+To read LZMA content, the module C<IO::Uncompress::UnLzma> must
+be installed.
+
+=item Xz (95)
+
+To read Xz content, the module C<IO::Uncompress::UnXz> must
+be installed.
+
+=item Zstandard (93)
+
+To read Zstandard content, the module C<IO::Uncompress::UnZstd> must
+be installed.
+
+=back
+
 =head1 Functional Interface
 
 A top-level function, C<unzip>, is provided to carry out
@@ -1449,7 +1515,7 @@ Open "membername" from the zip file for reading.
 
 =item C<< Efs => 0| 1 >>
 
-When this option is set to true AND the zip archive being read has 
+When this option is set to true AND the zip archive being read has
 the "Language Encoding Flag" (EFS) set, the member name is assumed to be encoded in UTF-8.
 
 If the member name in the zip archive is not valid UTF-8 when this optionn is true,
@@ -1797,7 +1863,7 @@ C<InputLength> option in the constructor.
 
 =head1 Importing
 
-No symbolic constants are required by this IO::Uncompress::Unzip at present.
+No symbolic constants are required by IO::Uncompress::Unzip at present.
 
 =over 5
 
@@ -1830,7 +1896,7 @@ stream at a time.
     my $status;
     for ($status = 1; $status > 0; $status = $u->nextStream())
     {
+
         my $name = $u->getHeaderInfo()->{Name};
         warn "Processing member $name\n" ;
 
@@ -1862,7 +1928,7 @@ The script is available from L<https://gist.github.com/eqhmcow/5389877>
 
 =head1 SUPPORT
 
-General feedback/questions/bug reports should be sent to 
+General feedback/questions/bug reports should be sent to
 L<https://github.com/pmqs/IO-Compress/issues> (preferred) or
 L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>.
 
@@ -1899,7 +1965,7 @@ See the Changes file.
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2005-2019 Paul Marquess. All rights reserved.
+Copyright (c) 2005-2020 Paul Marquess. All rights reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
index 9467cd3..205e032 100644 (file)
@@ -25,7 +25,7 @@ BEGIN
         if eval { require Test::NoWarnings ;  import Test::NoWarnings; 1 };
 
 
-    my $VERSION = '2.093';
+    my $VERSION = '2.096';
     my @NAMES = qw(
                        Compress::Raw::Bzip2
                        Compress::Raw::Zlib
index 7611da3..b0d6a43 100644 (file)
@@ -24,7 +24,7 @@ BEGIN {
     $extra = 1
         if eval { require Test::NoWarnings ;  import Test::NoWarnings; 1 };
 
-    plan tests => 227 + $extra ;
+    plan tests => 230 + $extra ;
 
     #use_ok('IO::Compress::Zip', qw(zip $ZipError :zip_method)) ;
     use_ok('IO::Compress::Zip', qw(:all)) ;
@@ -42,7 +42,7 @@ sub zipGetHeader
     my $got ;
 
     ok zip($in, \$out, %opts), "  zip ok" ;
-    ok unzip(\$out, \$got), "  unzip ok" 
+    ok unzip(\$out, \$got), "  unzip ok"
         or diag $UnzipError ;
     is $got, $content, "  got expected content" ;
 
@@ -57,7 +57,7 @@ sub zipGetHeader
     ok $gunz->close, "  closed ok" ;
 
     return $hdr ;
-    
+
 }
 
 {
@@ -73,7 +73,7 @@ sub zipGetHeader
     $mtime = (stat($file1))[9];
     # make sure that the zip file isn't created in the same
     # second as the input file
-    sleep 3 ; 
+    sleep 3 ;
     $hdr = zipGetHeader($file1, $content);
 
     is $hdr->{Name}, $file1, "  Name is '$file1'";
@@ -83,7 +83,7 @@ sub zipGetHeader
 
     writeFile($file1, $content);
     $mtime = (stat($file1))[9];
-    sleep 3 ; 
+    sleep 3 ;
     $hdr = zipGetHeader($file1, $content, Name => "abcde");
 
     is $hdr->{Name}, "abcde", "  Name is 'abcde'" ;
@@ -110,7 +110,7 @@ sub zipGetHeader
     title "Filehandle doesn't have default Name or Time" ;
     my $fh = new IO::File "< $file1"
         or diag "Cannot open '$file1': $!\n" ;
-    sleep 3 ; 
+    sleep 3 ;
     my $before = time ;
     $hdr = zipGetHeader($fh, $content);
     my $after = time ;
@@ -151,12 +151,12 @@ sub zipGetHeader
     $hdr = zipGetHeader($file1, $content, FilterName => sub {$_ = "abcde"});
     is $hdr->{Name}, "abcde", "  Name is 'abcde'" ;
 
-    $hdr = zipGetHeader($file1, $content, Name => $abs, 
+    $hdr = zipGetHeader($file1, $content, Name => $abs,
          CanonicalName => 1,
          FilterName => sub { s/joe/jim/ });
     is $hdr->{Name}, "fred/jim", "  Name is 'fred/jim'" ;
 
-    $hdr = zipGetHeader($file1, $content, Name => $abs, 
+    $hdr = zipGetHeader($file1, $content, Name => $abs,
          CanonicalName => 0,
          FilterName => sub { s/joe/jim/ });
     is $hdr->{Name}, File::Spec->catfile("", "fred", "jim"), "  Name is '/fred/jim'" ;
@@ -227,12 +227,12 @@ for my $stream (0, 1)
             my $content = "hello ";
             #writeFile($file1, $content);
 
-            my $status = zip(\$content => $file1 , 
-                               Method => $method, 
+            my $status = zip(\$content => $file1 ,
+                               Method => $method,
                                Stream => $stream,
                                Zip64  => $zip64);
 
-             ok $status, "  zip ok" 
+             ok $status, "  zip ok"
                 or diag $ZipError ;
 
             my $got ;
@@ -278,9 +278,9 @@ for my $stream (0, 1)
                             $file2 => $content2,
                           );
 
-            ok zip([$file1, $file2] => $zipfile , Method => $method, 
+            ok zip([$file1, $file2] => $zipfile , Method => $method,
                                                   Zip64  => $zip64,
-                                                  Stream => $stream), " zip ok" 
+                                                  Stream => $stream), " zip ok"
                 or diag $ZipError ;
 
             for my $file ($file1, $file2)
@@ -298,8 +298,8 @@ for my $stream (0, 1)
 {
     title "Regression: ods streaming issue";
 
-    # The file before meta.xml in test.ods is content.xml. 
-    # Issue was triggered because content.xml was stored 
+    # The file before meta.xml in test.ods is content.xml.
+    # Issue was triggered because content.xml was stored
     # as streamed and the code to walk the compressed streaming
     # content assumed that all of the input buffer was consumed
     # in a single call to "uncompr".
@@ -316,9 +316,41 @@ for my $stream (0, 1)
     ok unzip($zipfile => \$got, Name => $file), "  unzip $file ok"
         or diag $UnzipError ;
 
-    my $meta = readFile("$files/$file");
-    is $got, $meta, "  content ok";    
+    my $meta = '<?xml version="1.0" encoding="UTF-8"?>
+<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#" office:version="1.2"><office:meta><meta:creation-date>2018-12-25T11:36:11.437260543</meta:creation-date><dc:date>2018-12-25T11:36:55.657945697</dc:date><meta:editing-duration>PT54S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="1" meta:cell-count="3" meta:object-count="0"/><meta:generator>LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-3</meta:generator></office:meta></office:document-meta>';
+
+    is $got, $meta, "  content ok";
+
 }
 
-# TODO add more error cases
+{
+    title "Regression: odt non-streaming issue";
+    # https://github.com/pmqs/IO-Compress/issues/13
+
+    # Some programs (LibreOffice) mark entries as Streamed (bit 3 of the General Purpose Bit Flags field is set) ,
+    # but still fill out the Compressed Length, Uncompressed Length & CRC32 fields in the local file header
+
+    my $files = "./t/" ;
+    $files = "./" if $ENV{PERL_CORE} ;
+    $files .= "files/";
 
+    my $zipfile = "$files/testfile1.odt" ;
+    my $file = "manifest.rdf";
+
+    my $got;
+
+    ok unzip($zipfile => \$got, Name => $file), "  unzip $file ok"
+        or diag $UnzipError ;
+
+    my $meta = <<'EOM';
+<?xml version="1.0" encoding="utf-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+  <rdf:Description rdf:about="">
+    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#Document"/>
+  </rdf:Description>
+</rdf:RDF>
+EOM
+    is $got, $meta, "  content ok";
+}
+
+# TODO add more error cases
diff --git a/cpan/IO-Compress/t/files/testfile1.odt b/cpan/IO-Compress/t/files/testfile1.odt
new file mode 100644 (file)
index 0000000..b74f70a
Binary files /dev/null and b/cpan/IO-Compress/t/files/testfile1.odt differ