File: zipinfo.pl

package info (click to toggle)
libarchive-zip-perl 1.14-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 548 kB
  • ctags: 317
  • sloc: perl: 3,369; makefile: 45
file content (140 lines) | stat: -rw-r--r-- 3,918 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#! /usr/bin/perl -w
# Print out information about a ZIP file.
# Note that this buffers the entire file into memory!
# usage:
# perl examples/zipinfo.pl zipfile.zip

use strict;

use Data::Dumper ();
use FileHandle;
use Archive::Zip qw(:ERROR_CODES :CONSTANTS :PKZIP_CONSTANTS);
use Archive::Zip::BufferedFileHandle;

$| = 1;

# use constant END_OF_CENTRAL_DIRECTORY_SIGNATURE_STRING;
use constant CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE_STRING => pack( SIGNATURE_FORMAT,
	CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE );
use constant LOCAL_FILE_HEADER_SIGNATURE_STRING => pack( SIGNATURE_FORMAT,
	LOCAL_FILE_HEADER_SIGNATURE );

$Data::Dumper::Useqq = 1;	# enable double-quotes for string values
$Data::Dumper::Indent = 1;

my $zip = Archive::Zip->new();
my $zipFileName = shift(@ARGV);

my $fh = Archive::Zip::BufferedFileHandle->new();
$fh->readFromFile($zipFileName) or exit($!);

my $status = $zip->_findEndOfCentralDirectory($fh);
die("can't find EOCD\n") if $status != AZ_OK;

my $eocdPosition = $fh->tell( );

$status = $zip->_readEndOfCentralDirectory($fh);
die("can't read EOCD\n") if $status != AZ_OK;

my $zipDumper = Data::Dumper->new([$zip], ['ZIP']);
$zipDumper->Seen({ ref($fh), $fh });
print $zipDumper->Dump(), "\n";

my $expectedEOCDPosition = $zip->centralDirectoryOffsetWRTStartingDiskNumber()
	+ $zip->centralDirectorySize();

my $eocdOffset = $zip->{eocdOffset} = $eocdPosition - $expectedEOCDPosition;

if ($eocdOffset)
{
	printf "Expected EOCD at %d (0x%x) but found it at %d (0x%x)\n",
		($expectedEOCDPosition) x 2, ($eocdPosition) x 2;
}
else
{
	printf("Found EOCD at %d (0x%x)\n\n", ($eocdPosition) x 2);
}

my $contents = $fh->contents();
my $offset = $eocdPosition + $eocdOffset - 1;
my $cdPos;
my @members;
my $numberOfMembers = $zip->numberOfCentralDirectoriesOnThisDisk(); 
foreach my $n (0 .. $numberOfMembers - 1)
{
	my $index = $numberOfMembers - $n;
	$cdPos = rindex($contents,
		CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE_STRING, $offset);
	if ($cdPos < 0)
	{
		print "No central directory found for member #$index\n";
		last;
	}
	else
	{
		print "Found central directory for member #$index at $cdPos\n";
		$fh->seek($cdPos + SIGNATURE_LENGTH, 0);	# SEEK_SET
		my $newMember = $zip->ZIPMEMBERCLASS->_newFromZipFile(
			$fh, "($zipFileName)" );
		$status = $newMember->_readCentralDirectoryFileHeader();
		if ($status != AZ_OK and $status != AZ_STREAM_END)
		{
			printf "read CD header status=%d\n", $status;
			last;
		}
		unshift(@members, $newMember);

		my $memberDumper = Data::Dumper->new([$newMember], ['CDMEMBER' . $index ]);
		$memberDumper->Seen({ ref($fh), $fh });
		print $memberDumper->Dump(), "\n";
	}
	$offset = $cdPos - 1;
}

if ($cdPos >= 0 and 
	$cdPos != $zip->centralDirectoryOffsetWRTStartingDiskNumber())
{
	printf "Expected to find central directory at %d (0x%x), but found it at %d (0x%x)\n",
		($zip->centralDirectoryOffsetWRTStartingDiskNumber()) x 2,
		($cdPos) x 2;
}

print "\n";

# Now read the local headers

foreach my $n (0 .. $#members)
{
	my $member = $members[$n];
	$fh->seek($member->localHeaderRelativeOffset() + $eocdOffset + SIGNATURE_LENGTH, 0);
	$status = $member->_readLocalFileHeader();
	if ($status != AZ_OK and $status != AZ_STREAM_END)
	{
		printf "member %d read header status=%d\n", $n+1, $status;
		last;
	}

	my $memberDumper = Data::Dumper->new([$member], ['LHMEMBER' . ($n + 1)]);
	$memberDumper->Seen({ ref($fh), $fh });
	print $memberDumper->Dump(), "\n";

	my $endOfMember = $member->localHeaderRelativeOffset()
		+ $member->_localHeaderSize()
		+ $member->compressedSize();

	if ($endOfMember > $cdPos
		or ($n < $#members and 
			$endOfMember > $members[$n+1]->localHeaderRelativeOffset()))
	{
		print "Error: ";
	}
	printf("End of member: %d, CD at %d", $endOfMember, $cdPos);
	if ( $n < $#members )
	{
		printf(", next member starts at %d",
			$members[$n+1]->localHeaderRelativeOffset());
	}
	print("\n\n");
}

# vim: ts=4 sw=4