Archive::Zip fails to read archives with more than $Archive::Zip::ChunkSize bytes of garbage
after the end of directory signature. Attached is a modified version of
_findEndOfCentralDirectory which fixes this issue, by reading blocks of ChunkSize bytes
backwards from the end of the zipfile, rather than reading blocks of 512 bytes back to the
ChunkSize.
Subject: | eocd.pl |
sub _findEndOfCentralDirectory {
my $self = shift;
my $fh = shift;
my $data = '';
$fh->seek( 0, IO::Seekable::SEEK_END )
or return _ioError("seeking to end");
my $fileLength = $fh->tell();
if ( $fileLength < END_OF_CENTRAL_DIRECTORY_LENGTH + 4 ) {
return _formatError("file is too short");
}
my $seekOffset = 0;
my $pos = -1;
my $savedBytes = "";
for ( ; ; ) {
$seekOffset += $Archive::Zip::ChunkSize;
$seekOffset = $fileLength if ( $seekOffset > $fileLength );
$fh->seek( -$seekOffset, IO::Seekable::SEEK_END )
or return _ioError("seek failed");
my $bytesRead = $fh->read( $data, $Archive::Zip::ChunkSize );
if ( $bytesRead != $Archive::Zip::ChunkSize ) {
return _ioError("read failed");
}
$data .= $savedBytes;
$pos = rindex( $data, END_OF_CENTRAL_DIRECTORY_SIGNATURE_STRING );
$savedbytes= substr $data,0, (END_OF_CENTRAL_DIRECTORY_LENGTH - 1);
last
if ( $pos >= 0
or $seekOffset == $fileLength );
}
if ( $pos >= 0 ) {
$fh->seek( $pos - $Archive::Zip::ChunkSize, IO::Seekable::SEEK_CUR )
or return _ioError("seeking to EOCD");
return AZ_OK;
}
else {
return _formatError("can't find EOCD signature");
}
}