Skip Menu |

This queue is for tickets about the IO-Compress CPAN distribution.

Report information
The Basics
Id: 76495
Status: resolved
Priority: 0/
Queue: IO-Compress

People
Owner: Nobody in particular
Requestors: ppisar [...] redhat.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 2.049
Fixed in: (no value)



Subject: IO::Compress::Zip does not store uncompressed size properly
If I print more than 2**12+7 bytes into zip compressor, then the resulting zip stream while uncompressing reports bad uncompressed size. Tested with IO-Compress-2.049 on perl-5.14.2 on x86_64 Linux with threads. Maybe I cannot work with this module properly, but I cannot see any mistake. Try following code: #!/usr/bin/perl use strict; use warnings; use IO::Compress::Zip qw($ZipError); use IO::Uncompress::Unzip qw($UnzipError); use Data::Dumper; my $zip; my $input_length = 2**12+8; my $compressor = IO::Compress::Zip->new(\$zip, Zip64 => 1) or die "Constructing compressor failed: $ZipError\n"; $compressor->print('A' x $input_length); $compressor->close or die "Could not finish archive: $ZipError\n"; my $decompressor = IO::Uncompress::Unzip->new(\$zip) or die "Consctucting decompressor failed: $UnzipError\n"; my $output_length = ${$decompressor->getHeaderInfo}{'UncompressedLength'}; print "Expected length: " . $input_length . "\n"; print STDERR Dumper($output_length) . "\n"; if (ref $output_length) { $output_length = $output_length->get64bit; } print "Reported length: " . $output_length . "\n"; if ($input_length == $output_length) { exit 0; } else { exit 1; }
Hi your issue is caused by how you are creating the zip file. By default IO::Compress::Zip will created a streamed zip file. The assumption with a streamed zip file is you can't seek (Like when you are writing to a socket). One implication of using a streamed zip file is where it stores the compressed & uncompressed lengths. In a non-streamed zip file they are stored in a header data structure directly before the compressed payload. In a streamed zip file they are stored directly after the compressed data. When you open a zip file using IO::Uncompress::Unzip it immediately reads the header data before the compressed payload. So getHeaderInfo will not have the compressed/uncompressed lengths available. To sort out the issue just create the zip file in non-streaming mode, like this my $compressor = IO::Compress::Zip->new(\$zip, Zip64 => 1, Stream => 0) or die "Constructing compressor failed: $ZipError\n"; Paul
Subject: Re: [rt.cpan.org #76495] IO::Compress::Zip does not store uncompressed size properly
Date: Mon, 16 Apr 2012 08:16:23 +0200
To: Paul Marquess via RT <bug-IO-Compress [...] rt.cpan.org>
From: Petr Pisar <ppisar [...] redhat.com>
On Sat, Apr 14, 2012 at 02:45:04PM -0400, Paul Marquess via RT wrote: Show quoted text
> When you open a zip file using IO::Uncompress::Unzip it immediately > reads the header data before the compressed payload. So getHeaderInfo > will not have the compressed/uncompressed lengths available. > > To sort out the issue just create the zip file in non-streaming mode, >
Thanks for explaining. Can I ask how to get the sizes in case of archive in streamed mode? I guess the uncompressed size can be get by measurring the length of uncompressed data, but what about compressed size? Actually I cannot find any documentation. Even the header fields are not documented. And unpacking the 64-bit length by internal U64 module does not seem like the official API. Is there a better way, or is this just a thing to be done? -- Petr
Hi Petr, the answer really depends on what your use-case is. If all you want to do is find the uncompressed size I wouldn't use IO::Uncompress::Unzip. Parse the output from the commandline "unzip -ll zipfilename". If you are uncompressing anyway, you can use the size of the content read. Paul