2 # Print out information about a ZIP file.
3 # Note that this buffers the entire file into memory!
5 # perl examples/zipinfo.pl zipfile.zip
11 use Archive::Zip qw(:ERROR_CODES :CONSTANTS :PKZIP_CONSTANTS);
12 use Archive::Zip::BufferedFileHandle;
16 ### Workaround for a bug in version of Data::Dumper bundled
17 ### with some versions of Perl, which causes warnings when
18 ### calling ->Seen below.
19 if ( defined &Data::Dumper::init_refaddr_format ) {
20 Data::Dumper::init_refaddr_format();
23 # use constant END_OF_CENTRAL_DIRECTORY_SIGNATURE_STRING;
24 use constant CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE_STRING => pack( SIGNATURE_FORMAT,
25 CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE );
26 use constant LOCAL_FILE_HEADER_SIGNATURE_STRING => pack( SIGNATURE_FORMAT,
27 LOCAL_FILE_HEADER_SIGNATURE );
29 $Data::Dumper::Useqq = 1; # enable double-quotes for string values
30 $Data::Dumper::Indent = 1;
32 my $zip = Archive::Zip->new();
33 my $zipFileName = shift(@ARGV);
35 my $fh = Archive::Zip::BufferedFileHandle->new();
36 $fh->readFromFile($zipFileName) or exit($!);
38 my $status = $zip->_findEndOfCentralDirectory($fh);
39 die("can't find EOCD\n") if $status != AZ_OK;
41 my $eocdPosition = $fh->tell( );
43 $status = $zip->_readEndOfCentralDirectory($fh);
44 die("can't read EOCD\n") if $status != AZ_OK;
46 my $zipDumper = Data::Dumper->new([$zip], ['ZIP']);
47 $zipDumper->Seen({ ref($fh), $fh });
48 print $zipDumper->Dump(), "\n";
50 my $expectedEOCDPosition = $zip->centralDirectoryOffsetWRTStartingDiskNumber()
51 + $zip->centralDirectorySize();
53 my $eocdOffset = $zip->{eocdOffset} = $eocdPosition - $expectedEOCDPosition;
57 printf "Expected EOCD at %d (0x%x) but found it at %d (0x%x)\n",
58 ($expectedEOCDPosition) x 2, ($eocdPosition) x 2;
62 printf("Found EOCD at %d (0x%x)\n\n", ($eocdPosition) x 2);
65 my $contents = $fh->contents();
66 my $offset = $eocdPosition + $eocdOffset - 1;
69 my $numberOfMembers = $zip->numberOfCentralDirectoriesOnThisDisk();
70 foreach my $n (0 .. $numberOfMembers - 1)
72 my $index = $numberOfMembers - $n;
73 $cdPos = rindex($contents,
74 CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE_STRING, $offset);
77 print "No central directory found for member #$index\n";
82 print "Found central directory for member #$index at $cdPos\n";
83 $fh->seek($cdPos + SIGNATURE_LENGTH, 0); # SEEK_SET
84 my $newMember = $zip->ZIPMEMBERCLASS->_newFromZipFile(
85 $fh, "($zipFileName)" );
86 $status = $newMember->_readCentralDirectoryFileHeader();
87 if ($status != AZ_OK and $status != AZ_STREAM_END)
89 printf "read CD header status=%d\n", $status;
92 unshift(@members, $newMember);
94 my $memberDumper = Data::Dumper->new([$newMember], ['CDMEMBER' . $index ]);
95 $memberDumper->Seen({ ref($fh), $fh });
96 print $memberDumper->Dump(), "\n";
102 $cdPos != $zip->centralDirectoryOffsetWRTStartingDiskNumber())
104 printf "Expected to find central directory at %d (0x%x), but found it at %d (0x%x)\n",
105 ($zip->centralDirectoryOffsetWRTStartingDiskNumber()) x 2,
111 # Now read the local headers
113 foreach my $n (0 .. $#members)
115 my $member = $members[$n];
116 $fh->seek($member->localHeaderRelativeOffset() + $eocdOffset + SIGNATURE_LENGTH, 0);
117 $status = $member->_readLocalFileHeader();
118 if ($status != AZ_OK and $status != AZ_STREAM_END)
120 printf "member %d read header status=%d\n", $n+1, $status;
124 my $memberDumper = Data::Dumper->new([$member], ['LHMEMBER' . ($n + 1)]);
125 $memberDumper->Seen({ ref($fh), $fh });
126 print $memberDumper->Dump(), "\n";
128 my $endOfMember = $member->localHeaderRelativeOffset()
129 + $member->_localHeaderSize()
130 + $member->compressedSize();
132 if ($endOfMember > $cdPos
133 or ($n < $#members and
134 $endOfMember > $members[$n+1]->localHeaderRelativeOffset()))
138 printf("End of member: %d, CD at %d", $endOfMember, $cdPos);
139 if ( $n < $#members )
141 printf(", next member starts at %d",
142 $members[$n+1]->localHeaderRelativeOffset());