So this FAQ is an attempt to cut down on the number of personal answers I have to give. At least I can now say "You did read the FAQ, right?".
The questions are not in any particular order. The answers assume the current version of Archive::Zip; some of the answers depend on newly added/fixed functionality.
A: This has become something of a FAQ. Basically, RedHat broke some versions of Perl by setting LANG to UTF8. They apparently have a fixed version out as an update.
You might try running CPAN or creating your Makefile after exporting the LANG environment variable as
"LANG=C"
<https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=87682>
A: Some things to make sure of:
A: Have you looked in the "examples/" directory yet? It contains:
A: Because Archive::Zip doesn't (and can't, generally) read file contents into memory, the original Zip file is required to stay around until the writing of the new file is completed.
The best way to do this is to write the Zip to a temporary file and then rename the temporary file to have the old name (possibly after deleting the old one).
Archive::Zip v1.02 added the archive methods "overwrite()" and "overwriteAs()" to do this simply and carefully.
See "examples/updateZip.pl" for an example of this technique.
A: Mostly because Perl doesn't give cross-platform access to creation time. Indeed, many systems (like Unix) don't support such a concept. However, if yours does, you can easily set it. Get the modification time from the member using "lastModTime()".
A: No.
There is a distinction between Unix gzip files, and Zip archives that also can use the gzip compression.
Depending on the format of the gzip file, you can use Compress::Raw::Zlib, or Archive::Tar to decompress it (and de-archive it in the case of Tar files).
You can unzip PKZIP/WinZip/etc/ archives using Archive::Zip (that's what it's for) as long as any compressed members are compressed using Deflate compression.
A: You can use the Archive::Zip::addTree*() methods:
use Archive::Zip; my $zip = Archive::Zip->new(); # add all readable files and directories below . as xyz/* $zip->addTree( '.', 'xyz' ); # add all readable plain files below /abc as def/* $zip->addTree( '/abc', 'def', sub { -f && -r } ); # add all .c files below /tmp as stuff/* $zip->addTreeMatching( '/tmp', 'stuff', '\.c$' ); # add all .o files below /tmp as stuff/* if they aren't writable $zip->addTreeMatching( '/tmp', 'stuff', '\.o$', sub { ! -w } ); # add all .so files below /tmp that are smaller than 200 bytes as stuff/* $zip->addTreeMatching( '/tmp', 'stuff', '\.o$', sub { -s < 200 } ); # and write them into a file $zip->writeToFileNamed('xxx.zip');
A: You can use the Archive::Zip::extractTree() method: ??? ||
# now extract the same files into /tmpx $zip->extractTree( 'stuff', '/tmpx' );
A: You can use the Archive::Zip::updateTree() method that was added in version 1.09.
A: Get over it. This is a result of the Zip format storing times in DOS format, which has a resolution of only two seconds.
A: If this is important to you, please submit patches to read the various Extra Fields that encode times with time zones. I'm just using the DOS Date/Time, which doesn't have a time zone.
A: Yes. You can write a self-extracting archive stub (that is, a version of unzip) to the output filehandle that you pass to writeToFileHandle(). See examples/selfex.pl for how to write a self-extracting archive.
However, you should understand that this will only work on one kind of platform (the one for which the stub was compiled).
A: I added code for this for the Amavis virus scanner. You can query archives for their 'eocdOffset' property, which should be 0:
if ($zip->eocdOffset > 0) { warn($zip->eocdOffset . " bytes of garbage at beginning or within Zip") }
When members are extracted, this offset will be used to adjust the start of the member if necessary.
error: Unsupported compression combination: read 6, write 0
A: You can't uncompress this archive member. Archive::Zip only supports uncompressed members, and compressed members that are compressed using the compression supported by Compress::Raw::Zlib. That means only Deflated and Stored members.
Your file is compressed using the Shrink format, which is not supported by Compress::Raw::Zlib.
You could, perhaps, use a command-line UnZip program (like the Info-Zip one) to extract this.
A: With some other program or library. Archive::Zip doesn't support decryption, and probably never will (unless you write it).
A: If you try to decompress the file, the gzip streams will report errors if you have garbage. Most of the time.
If you try to open the file and a central directory structure can't be found, an error will be reported.
When a file is being read, if we can't find a proper PK.. signature in the right places we report a format error.
If there is added garbage at the beginning of a Zip file (as inserted by some viruses), you can find out about it, but Archive::Zip will ignore it, and you can still use the archive. When it gets written back out the added stuff will be gone.
There are two ready-to-use utilities in the examples directory that can be used to test file integrity, or that you can use as examples for your own code:
A: As far as I can tell, this is not disallowed by the Zip spec. If you think it's a bad idea, check for it yourself:
$zip->addFile($someFile, $someName) unless $zip->memberNamed($someName);
I can even imagine cases where this might be useful (for instance, multiple versions of files).
A: There is no standard way to represent these in the Zip file format. If you want to send me code to properly handle the various extra fields that have been used to represent these through the years, I'll look at it.
A: Probably not, unless I get lots of extra time. But there's no reason you can't install the version from CPAN. Archive::Zip is pure Perl, so all you need is NMAKE, which you can get for free from Microsoft (see the FAQ in the ActiveState documentation for details on how to install CPAN modules).
A: Because they're already compressed.
A: First, try the newest version of Compress::Raw::Zlib. I know of Windows-related problems prior to v1.14 of that library.
A: Use "IO::String" and the "readFromFileHandle()" and "writeToFileHandle()" methods. See "examples/readScalar.pl" and "examples/writeScalar.pl".
A: This is not currently supported, though writing to a stream is.