|
Packit |
0bf95d |
#! /usr/bin/perl -w
|
|
Packit |
0bf95d |
# Print out information about a ZIP file.
|
|
Packit |
0bf95d |
# Note that this buffers the entire file into memory!
|
|
Packit |
0bf95d |
# usage:
|
|
Packit |
0bf95d |
# perl examples/zipinfo.pl zipfile.zip
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
use strict;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
use Data::Dumper ();
|
|
Packit |
0bf95d |
use FileHandle;
|
|
Packit |
0bf95d |
use Archive::Zip qw(:ERROR_CODES :CONSTANTS :PKZIP_CONSTANTS);
|
|
Packit |
0bf95d |
use Archive::Zip::BufferedFileHandle;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
$| = 1;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
### Workaround for a bug in version of Data::Dumper bundled
|
|
Packit |
0bf95d |
### with some versions of Perl, which causes warnings when
|
|
Packit |
0bf95d |
### calling ->Seen below.
|
|
Packit |
0bf95d |
if (defined &Data::Dumper::init_refaddr_format) {
|
|
Packit |
0bf95d |
Data::Dumper::init_refaddr_format();
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
# use constant END_OF_CENTRAL_DIRECTORY_SIGNATURE_STRING;
|
|
Packit |
0bf95d |
use constant CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE_STRING =>
|
|
Packit |
0bf95d |
pack(SIGNATURE_FORMAT, CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE);
|
|
Packit |
0bf95d |
use constant LOCAL_FILE_HEADER_SIGNATURE_STRING =>
|
|
Packit |
0bf95d |
pack(SIGNATURE_FORMAT, LOCAL_FILE_HEADER_SIGNATURE);
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
$Data::Dumper::Useqq = 1; # enable double-quotes for string values
|
|
Packit |
0bf95d |
$Data::Dumper::Indent = 1;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $zip = Archive::Zip->new();
|
|
Packit |
0bf95d |
my $zipFileName = shift(@ARGV);
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $fh = Archive::Zip::BufferedFileHandle->new();
|
|
Packit |
0bf95d |
$fh->readFromFile($zipFileName) or exit($!);
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $status = $zip->_findEndOfCentralDirectory($fh);
|
|
Packit |
0bf95d |
die("can't find EOCD\n") if $status != AZ_OK;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $eocdPosition = $fh->tell();
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
$status = $zip->_readEndOfCentralDirectory($fh);
|
|
Packit |
0bf95d |
die("can't read EOCD\n") if $status != AZ_OK;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $zipDumper = Data::Dumper->new([$zip], ['ZIP']);
|
|
Packit |
0bf95d |
$zipDumper->Seen({ref($fh), $fh});
|
|
Packit |
0bf95d |
print $zipDumper->Dump(), "\n";
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $expectedEOCDPosition =
|
|
Packit |
0bf95d |
$zip->centralDirectoryOffsetWRTStartingDiskNumber() +
|
|
Packit |
0bf95d |
$zip->centralDirectorySize();
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $eocdOffset = $zip->{eocdOffset} = $eocdPosition - $expectedEOCDPosition;
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
if ($eocdOffset) {
|
|
Packit |
0bf95d |
printf "Expected EOCD at %d (0x%x) but found it at %d (0x%x)\n",
|
|
Packit |
0bf95d |
($expectedEOCDPosition) x 2, ($eocdPosition) x 2;
|
|
Packit |
0bf95d |
} else {
|
|
Packit |
0bf95d |
printf("Found EOCD at %d (0x%x)\n\n", ($eocdPosition) x 2);
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $contents = $fh->contents();
|
|
Packit |
0bf95d |
my $offset = $eocdPosition + $eocdOffset - 1;
|
|
Packit |
0bf95d |
my $cdPos;
|
|
Packit |
0bf95d |
my @members;
|
|
Packit |
0bf95d |
my $numberOfMembers = $zip->numberOfCentralDirectoriesOnThisDisk();
|
|
Packit |
0bf95d |
foreach my $n (0 .. $numberOfMembers - 1) {
|
|
Packit |
0bf95d |
my $index = $numberOfMembers - $n;
|
|
Packit |
0bf95d |
$cdPos = rindex($contents,
|
|
Packit |
0bf95d |
CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE_STRING, $offset);
|
|
Packit |
0bf95d |
if ($cdPos < 0) {
|
|
Packit |
0bf95d |
print "No central directory found for member #$index\n";
|
|
Packit |
0bf95d |
last;
|
|
Packit |
0bf95d |
} else {
|
|
Packit |
0bf95d |
print "Found central directory for member #$index at $cdPos\n";
|
|
Packit |
0bf95d |
$fh->seek($cdPos + SIGNATURE_LENGTH, 0); # SEEK_SET
|
|
Packit |
0bf95d |
my $newMember =
|
|
Packit |
0bf95d |
Archive::Zip::Member->_newFromZipFile($fh, "($zipFileName)");
|
|
Packit |
0bf95d |
$status = $newMember->_readCentralDirectoryFileHeader();
|
|
Packit |
0bf95d |
if ($status != AZ_OK and $status != AZ_STREAM_END) {
|
|
Packit |
0bf95d |
printf "read CD header status=%d\n", $status;
|
|
Packit |
0bf95d |
last;
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
unshift(@members, $newMember);
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $memberDumper =
|
|
Packit |
0bf95d |
Data::Dumper->new([$newMember], ['CDMEMBER' . $index]);
|
|
Packit |
0bf95d |
$memberDumper->Seen({ref($fh), $fh});
|
|
Packit |
0bf95d |
print $memberDumper->Dump(), "\n";
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
$offset = $cdPos - 1;
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
if ( $cdPos >= 0
|
|
Packit |
0bf95d |
and $cdPos != $zip->centralDirectoryOffsetWRTStartingDiskNumber()) {
|
|
Packit |
0bf95d |
printf
|
|
Packit |
0bf95d |
"Expected to find central directory at %d (0x%x), but found it at %d (0x%x)\n",
|
|
Packit |
0bf95d |
($zip->centralDirectoryOffsetWRTStartingDiskNumber()) x 2,
|
|
Packit |
0bf95d |
($cdPos) x 2;
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
print "\n";
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
# Now read the local headers
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
foreach my $n (0 .. $#members) {
|
|
Packit |
0bf95d |
my $member = $members[$n];
|
|
Packit |
0bf95d |
$fh->seek(
|
|
Packit |
0bf95d |
$member->localHeaderRelativeOffset() + $eocdOffset + SIGNATURE_LENGTH,
|
|
Packit |
0bf95d |
0);
|
|
Packit |
0bf95d |
$status = $member->_readLocalFileHeader();
|
|
Packit |
0bf95d |
if ($status != AZ_OK and $status != AZ_STREAM_END) {
|
|
Packit |
0bf95d |
printf "member %d read header status=%d\n", $n + 1, $status;
|
|
Packit |
0bf95d |
last;
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $memberDumper = Data::Dumper->new([$member], ['LHMEMBER' . ($n + 1)]);
|
|
Packit |
0bf95d |
$memberDumper->Seen({ref($fh), $fh});
|
|
Packit |
0bf95d |
print $memberDumper->Dump(), "\n";
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
my $endOfMember =
|
|
Packit |
0bf95d |
$member->localHeaderRelativeOffset() +
|
|
Packit |
0bf95d |
$member->_localHeaderSize() +
|
|
Packit |
0bf95d |
$member->compressedSize();
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
if (
|
|
Packit |
0bf95d |
$endOfMember > $cdPos
|
|
Packit |
0bf95d |
or ( $n < $#members
|
|
Packit |
0bf95d |
and $endOfMember > $members[$n + 1]->localHeaderRelativeOffset())
|
|
Packit |
0bf95d |
) {
|
|
Packit |
0bf95d |
print "Error: ";
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
printf("End of member: %d, CD at %d", $endOfMember, $cdPos);
|
|
Packit |
0bf95d |
if ($n < $#members) {
|
|
Packit |
0bf95d |
printf(", next member starts at %d",
|
|
Packit |
0bf95d |
$members[$n + 1]->localHeaderRelativeOffset());
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
print("\n\n");
|
|
Packit |
0bf95d |
}
|
|
Packit |
0bf95d |
|
|
Packit |
0bf95d |
# vim: ts=4 sw=4
|