App-zipdetails
view release on metacpan or search on metacpan
bin/zipdetails view on Meta::CPAN
my $outerEntry = $LocalDirectory->getByLocalOffset($loc);
say "Local Header for '" . $outerEntry->outputFilename . "' at offset " . decimalHex0x($loc) . " has $count nested Local Headers";
for my $n ( @{ $nested{$loc} } )
{
my $innerEntry = $LocalDirectory->getByLocalOffset($n);
say "# Nested Local Header for filename '" . $innerEntry->outputFilename . "' is at Offset " . decimalHex0x($n) ;
}
}
}
if (keys %bomb)
{
# Central Directory knows about these, so this is a zipbomb
error undef, "Possible zipbomb -- Nested Local Entries found";
for my $loc (sort keys %bomb)
{
my $count = scalar @{ $bomb{$loc} };
my $outerEntry = $LocalDirectory->getByLocalOffset($loc);
say "# Local Header for '" . $outerEntry->outputFilename . "' at offset " . decimalHex0x($loc) . " has $count nested Local Headers";
my $table = new SimpleTable;
$table->addHeaderRow('Offset', 'Filename');
$table->addDataRow(decimalHex0x($_), $LocalDirectory->getByLocalOffset($_)->outputFilename)
for sort @{ $bomb{$loc} } ;
$table->display();
delete $cleanCentralEntries{ $_ }
for grep { defined $_ }
map { $CentralDirectory->{byLocalOffset}{$_}{centralHeaderOffset} }
@{ $bomb{$loc} } ;
}
}
}
# Check if contents of local headers match with Central Headers
#
# When Central Header encryption is used the local header values are masked (see APPNOTE 6.3.10, sec 4)
# In this usecase the Central Header will appear to be absent
#
# key fields
# filename, compressed/uncompressed lengths, crc, compression method
{
for my $centralEntry ( sort { $a->centralHeaderOffset() <=> $b->centralHeaderOffset() } values %cleanCentralEntries )
{
my $localOffset = $centralEntry->localHeaderOffset;
my $localEntry = $LocalDirectory->getByLocalOffset($localOffset);
next
unless $localEntry;
state $fields = [
# field name offset display name stringify
['filename', ZIP_CD_FILENAME_OFFSET,
'Filename', undef, ],
['extractVersion', 7, 'Extract Zip Spec', sub { decimalHex0xUndef($_[0]) . " " . decodeZipVer($_[0]) }, ],
['generalPurposeFlags', 8, 'General Purpose Flag', \&decimalHex0xUndef, ],
['compressedMethod', 10, 'Compression Method', sub { decimalHex0xUndef($_[0]) . " " . getcompressionMethodName($_[0]) }, ],
['lastModDateTime', 12, 'Modification Time', sub { decimalHex0xUndef($_[0]) . " " . LastModTime($_[0]) }, ],
['crc32', 16, 'CRC32', \&decimalHex0xUndef, ],
['compressedSize', 20, 'Compressed Size', \&decimalHex0xUndef, ],
['uncompressedSize', 24, 'Uncompressed Size', \&decimalHex0xUndef, ],
] ;
my $table = new SimpleTable;
$table->addHeaderRow('Field Name', 'Central Offset', 'Central Value', 'Local Offset', 'Local Value');
for my $data (@$fields)
{
my ($field, $offset, $name, $stringify) = @$data;
# if the local header uses streaming and we are running a scan/walk, the compressed/uncompressed sizes will not be known
my $localValue = $localEntry->{$field} ;
my $centralValue = $centralEntry->{$field};
if (($localValue // '-1') ne ($centralValue // '-2'))
{
if ($stringify)
{
$localValue = $stringify->($localValue);
$centralValue = $stringify->($centralValue);
}
$table->addDataRow($name,
decimalHex0xUndef($centralEntry->centralHeaderOffset() + $offset),
$centralValue,
decimalHex0xUndef($localOffset+$offset),
$localValue);
}
}
my $badFields = $table->hasData;
if ($badFields)
{
error undef, "Found $badFields Field Mismatch for Filename '". $centralEntry->outputFilename . "'";
$table->display();
}
}
}
}
elsif ($CentralDirectory->exists())
{
my @messages = "Central Directory exists, but Local Directory not found" ;
push @messages , "Try running with --walk' or '--scan' options"
unless $opt_scan || $opt_walk ;
error undef, @messages;
}
elsif ($LocalDirectory->exists())
{
if ($CentralDirectory->isEncryptedCD())
{
warning undef, "Local Directory exists, but Central Directory is encrypted"
}
else
{
error undef, "Local Directory exists, but Central Directory not found"
}
bin/zipdetails view on Meta::CPAN
my ($bgp, $gpFlag) = read_v();
my ($bcm, $compressedMethod) = read_v();
out $bgp, "General Purpose Flag", Value_v($gpFlag) ;
GeneralPurposeBits($compressedMethod, $gpFlag);
my $LanguageEncodingFlag = $gpFlag & ZIP_GP_FLAG_LANGUAGE_ENCODING ;
my $streaming = $gpFlag & ZIP_GP_FLAG_STREAMING_MASK ;
$localEntry->languageEncodingFlag($LanguageEncodingFlag) ;
out $bcm, "Compression Method", compressionMethod($compressedMethod) ;
info $FH->tell() - 2, "Unknown 'Compression Method' ID " . decimalHex0x($compressedMethod, 2)
if ! defined $ZIP_CompressionMethods{$compressedMethod} ;
my $lastMod = out_V "Modification Time", sub { LastModTime($_[0]) };
my $crc = out_V "CRC";
# Weak encryption if
# * encrypt flag (bit 0) set in General Purpose Flags
# * strong encrypt (bit ) not set in General Purpose Flags
# * not using AES encryption (compression method 99)
my $weakEncryption = ($gpFlag & ZIP_GP_FLAG_ALL_ENCRYPT) == ZIP_GP_FLAG_ENCRYPTED_MASK &&
$compressedMethod != ZIP_CM_AES;
# Weak encryption uses the CRC value even when streaming is in play.
# This conflicts with appnote 6.3.10 section 4.4.4
warning $FH->tell() - 4, "CRC field should be zero when streaming is enabled"
if $streaming && $crc != 0 && ! $weakEncryption;
my $compressedSize = out_V "Compressed Size";
# warning $FH->tell(), "Compressed Size should be zero when streaming is enabled";
my $uncompressedSize = out_V "Uncompressed Size";
# warning $FH->tell(), "Uncompressed Size should be zero when streaming is enabled";
my $filenameLength = out_v "Filename Length";
if ($filenameLength == 0)
{
info $FH->tell()- 2, "Zero Length filename";
}
my $extraLength = out_v "Extra Length";
my $filename = '';
if ($filenameLength)
{
need $filenameLength, Signatures::name($signature), 'Filename';
myRead(my $raw_filename, $filenameLength);
$localEntry->filename($raw_filename) ;
$filename = outputFilename($raw_filename, $LanguageEncodingFlag);
$localEntry->outputFilename($filename);
}
$localEntry->localHeaderOffset($locHeaderOffset) ;
$localEntry->offsetStart($locHeaderOffset) ;
$localEntry->compressedSize($compressedSize) ;
$localEntry->uncompressedSize($uncompressedSize) ;
$localEntry->extractVersion($extractVer);
$localEntry->generalPurposeFlags($gpFlag);
$localEntry->lastModDateTime($lastMod);
$localEntry->crc32($crc) ;
$localEntry->zip64ExtraPresent($cdZip64) ;
$localEntry->zip64SizesPresent($zip64Sizes) ;
$localEntry->compressedMethod($compressedMethod) ;
$localEntry->streamed($gpFlag & ZIP_GP_FLAG_STREAMING_MASK) ;
$localEntry->std_localHeaderOffset($locHeaderOffset + $PREFIX_DELTA) ;
$localEntry->std_compressedSize($compressedSize) ;
$localEntry->std_uncompressedSize($uncompressedSize) ;
$localEntry->std_diskNumber(0) ;
if ($extraLength)
{
need $extraLength, Signatures::name($signature), 'Extra';
walkExtra($extraLength, $localEntry);
}
# Defer test for directory payload until Central Header processing.
# Need to have external file attributes to deal with some edge conditions.
# # APPNOTE 6.3.10, sec 4.3.8
# warning $FH->tell - $filenameLength, "Directory '$filename' must not have a payload"
# if ! $streaming && $filename =~ m#/$# && $localEntry->uncompressedSize ;
my @msg ;
# if ($cdZip64 && ! $ZIP64)
# {
# # Central directory said this was Zip64
# # some zip files don't have the Zip64 field in the local header
# # seems to be a streaming issue.
# push @msg, "Missing Zip64 extra field in Local Header #$hexHdrCount\n";
# if (! $zip64Sizes)
# {
# # Central has a ZIP64 entry that doesn't have sizes
# # Local doesn't have a Zip 64 at all
# push @msg, "Unzip may complain about 'overlapped components' #$hexHdrCount\n";
# }
# else
# {
# $ZIP64 = 1
# }
# }
my $minizip_encrypted = $localEntry->minizip_secure;
my $pk_encrypted = ($gpFlag & ZIP_GP_FLAG_STRONG_ENCRYPTED_MASK) && $compressedMethod != ZIP_CM_AES && ! $minizip_encrypted;
# Detecting PK strong encryption from a local header is a bit convoluted.
# Cannot just use ZIP_GP_FLAG_ENCRYPTED_CD because minizip also uses this bit.
# so jump through some hoops
# extract ver is >= 5.0'
# all the encryption flags are set in gpflags
# TODO - add zero lengths for crc, compressed & uncompressed
if (($gpFlag & ZIP_GP_FLAG_ALL_ENCRYPT) == ZIP_GP_FLAG_ALL_ENCRYPT && $extractVer >= 0x32 )
{
$CentralDirectory->setPkEncryptedCD()
}
bin/zipdetails view on Meta::CPAN
0x0C => 'Socket', # 0x0C 0b1100
0x0A => 'Symbolic Link', # 0x0A 0b1010
0x08 => 'Regular File', # 0x08 0b1000
0x06 => 'Block Device', # 0x06 0b0110
0x04 => 'Directory', # 0x04 0b0100
0x02 => 'Character Device', # 0x02 0b0010
0x01 => 'FIFO', # 0x01 0b0001
};
my $got = $masks->{$not_rwx} // 'Unknown Unix attrib' ;
out1 "[Bits 28-31]", Value_C($not_rwx) . " '$got'"
}
}
}
elsif ($native_attrib)
{
out1 "[Bits 24-31]", Value_v($native_attrib) . " 'Unknown attributes for OS ID $made_by'"
}
my ($d, $locHeaderOffset) = read_V();
my $out = Value_V($locHeaderOffset);
my $std_localHeaderOffset = $locHeaderOffset;
if ($locHeaderOffset != MAX32)
{
testPossiblePrefix($locHeaderOffset, ZIP_LOCAL_HDR_SIG);
if ($PREFIX_DELTA)
{
$out .= " [Actual Offset is " . Value_V($locHeaderOffset + $PREFIX_DELTA) . "]"
}
}
out $d, "Local Header Offset", $out;
if ($locHeaderOffset != MAX32)
{
my $commonMessage = "'Local Header Offset' field in '" . Signatures::name($signature) . "' is invalid";
$locHeaderOffset = checkOffsetValue($locHeaderOffset, $startRecordOffset, 0, $commonMessage, $startRecordOffset + CentralDirectoryEntry::Offset_RelativeOffsetToLocal(), ZIP_LOCAL_HDR_SIG) ;
}
my $filename = '';
if ($filenameLength)
{
need $filenameLength, Signatures::name($signature), 'Filename';
myRead(my $raw_filename, $filenameLength);
$cdEntry->filename($raw_filename) ;
$filename = outputFilename($raw_filename, $LanguageEncodingFlag);
$cdEntry->outputFilename($filename);
}
$cdEntry->centralHeaderOffset($cdEntryOffset) ;
$cdEntry->localHeaderOffset($locHeaderOffset) ;
$cdEntry->compressedSize($compressedSize) ;
$cdEntry->uncompressedSize($uncompressedSize) ;
$cdEntry->zip64ExtraPresent(undef) ; #$cdZip64; ### FIX ME
$cdEntry->zip64SizesPresent(undef) ; # $zip64Sizes; ### FIX ME
$cdEntry->extractVersion($extractVer);
$cdEntry->generalPurposeFlags($gpFlag);
$cdEntry->compressedMethod($compressedMethod) ;
$cdEntry->lastModDateTime($lastMod);
$cdEntry->crc32($crc) ;
$cdEntry->inCentralDir(1) ;
$cdEntry->std_localHeaderOffset($std_localHeaderOffset) ;
$cdEntry->std_compressedSize($std_compressedSize) ;
$cdEntry->std_uncompressedSize($std_uncompressedSize) ;
$cdEntry->std_diskNumber($std_disk_start) ;
if ($extraLength)
{
need $extraLength, Signatures::name($signature), 'Extra';
walkExtra($extraLength, $cdEntry);
}
# $cdEntry->endCentralHeaderOffset($FH->tell() - 1);
# Can only validate for directory after zip64 data is read
validateDirectory($cdEntryOffset, $filename, $extractVer, $made_by,
$cdEntry->compressedSize, $cdEntry->uncompressedSize, $ext_file_attrib);
if ($comment_length)
{
need $comment_length, Signatures::name($signature), 'Comment';
my $comment ;
myRead($comment, $comment_length);
outputFilename $comment, $LanguageEncodingFlag, "Comment";
$cdEntry->comment($comment);
}
$cdEntry->offsetStart($cdEntryOffset) ;
$cdEntry->offsetEnd($FH->tell() - 1) ;
$CentralDirectory->addEntry($cdEntry);
return { 'encapsulated' => $cdEntry ? $cdEntry->encapsulated() : 0};
}
sub decodeZipVer
{
my $ver = shift ;
return ""
if ! defined $ver;
my $sHi = int($ver /10) ;
my $sLo = $ver % 10 ;
"$sHi.$sLo";
}
sub decodeOS
{
my $ver = shift ;
$OS_Lookup{$ver} || "Unknown" ;
}
sub Zip64EndCentralHeader
bin/zipdetails view on Meta::CPAN
if ($display && !$entry->streamed && ! full16 $entry->std_diskNumber)
{
info $FH->tell() - 4, "'$fieldName' should not be present in the ZIP64 extra field.",
"Corresponding field from Central Header is not set to 0xFFFF, value is " . decimalHex0x($entry->diskNumber);
}
$entry->zip64_diskNumberPresent(1);
$entry->diskNumber($value);
}
if (length $zip64Extended)
{
if ($display)
{
out2 $zip64Extended, "Unexpected Data", hexDump16 $zip64Extended ;
info $fieldOffset, extraFieldIdentifier($extraID) . ": Unexpected Data: " . decimalHex0x(length $zip64Extended) . " bytes";
}
}
}
sub Ntfs2Unix
{
my $m = shift;
my $v = shift;
# NTFS offset is 19DB1DED53E8000
my $hex = Value_Q($v) ;
# Treat empty value as special case
# Could decode to 1 Jan 1601
return "$hex 'No Date/Time'"
if $v == 0;
$v -= 0x19DB1DED53E8000 ;
my $ns = ($v % 10000000) * 100;
my $elapse = int ($v/10000000);
return "$hex '" . getT($elapse) .
" " . sprintf("%0dns'", $ns);
}
sub decode_NTFS_Filetimes
{
my $extraID = shift ;
my $len = shift;
my $entry = shift;
out_V " Reserved";
out_v " Tag1";
out_v " Size1" ;
my ($m, $s1) = read_Q;
out $m, " Mtime", Ntfs2Unix($m, $s1);
my ($a, $s3) = read_Q;
out $a, " Atime", Ntfs2Unix($a, $s3);
my ($c, $s2) = read_Q;
out $c, " Ctime", Ntfs2Unix($c, $s2);
}
sub OpenVMS_DateTime
{
my $ix = shift;
my $tag = shift;
my $size = shift;
# VMS epoch is 17 Nov 1858
# Offset to Unix Epoch is -0x7C95674C3DA5C0 (-35067168005400000)
my ($data, $value) = read_Q();
my $datetime = "No Date Time'";
if ($value != 0)
{
my $v = $value - 0x007C95674C3DA5C0 ;
my $ns = ($v % 10000000) * 100 ;
my $seconds = int($v / 10000000) ;
$datetime = getT($seconds) .
" " . sprintf("%0dns'", $ns);
}
out2 $data, " Attribute", Value_Q($value) . " '$datetime";
}
sub OpenVMS_DumpBytes
{
my $ix = shift;
my $tag = shift;
my $size = shift;
myRead(my $data, $size);
out($data, " Attribute", hexDump16($data));
}
sub OpenVMS_4ByteValue
{
my $ix = shift;
my $tag = shift;
my $size = shift;
my ($data, $value) = read_V();
out2 $data, " Attribute", Value_V($value);
}
sub OpenVMS_UCHAR
{
my $ix = shift;
my $tag = shift;
my $size = shift;
state $FCH = {
0 => 'FCH$M_WASCONTIG',
1 => 'FCH$M_NOBACKUP',
2 => 'FCH$M_WRITEBACK',
3 => 'FCH$M_READCHECK',
4 => 'FCH$M_WRITCHECK',
5 => 'FCH$M_CONTIGB',
6 => 'FCH$M_LOCKED',
6 => 'FCH$M_CONTIG',
11 => 'FCH$M_BADACL',
12 => 'FCH$M_SPOOL',
13 => 'FCH$M_DIRECTORY',
14 => 'FCH$M_BADBLOCK',
15 => 'FCH$M_MARKDEL',
16 => 'FCH$M_NOCHARGE',
17 => 'FCH$M_ERASE',
18 => 'FCH$M_SHELVED',
20 => 'FCH$M_SCRATCH',
21 => 'FCH$M_NOMOVE',
22 => 'FCH$M_NOSHELVABLE',
} ;
my ($data, $value) = read_V();
out2 $data, " Attribute", Value_V($value);
for my $bit ( sort { $a <=> $b } keys %{ $FCH } )
{
# print "$bit\n";
if ($value & (1 << $bit) )
{
out1 " [Bit $bit]", $FCH->{$bit} ;
}
}
}
sub OpenVMS_2ByteValue
{
my $ix = shift;
my $tag = shift;
my $size = shift;
my ($data, $value) = read_v();
out2 $data, " Attribute", Value_v($value);
}
sub OpenVMS_revision
{
my $ix = shift;
my $tag = shift;
my $size = shift;
my ($data, $value) = read_v();
out2 $data, " Attribute", Value_v($value) . "'Revision Count " . Value_v($value) . "'";
}
sub decode_OpenVMS
{
my $extraID = shift ;
my $len = shift;
my $entry = shift;
state $openVMS_tags = {
0x04 => [ 'ATR$C_RECATTR', \&OpenVMS_DumpBytes ],
0x03 => [ 'ATR$C_UCHAR', \&OpenVMS_UCHAR ],
0x11 => [ 'ATR$C_CREDATE', \&OpenVMS_DateTime ],
0x12 => [ 'ATR$C_REVDATE', \&OpenVMS_DateTime ],
0x13 => [ 'ATR$C_EXPDATE', \&OpenVMS_DateTime ],
0x14 => [ 'ATR$C_BAKDATE', \&OpenVMS_DateTime ],
0x0D => [ 'ATR$C_ASCDATES', \&OpenVMS_revision ],
0x15 => [ 'ATR$C_UIC', \&OpenVMS_4ByteValue ],
0x16 => [ 'ATR$C_FPRO', \&OpenVMS_DumpBytes ],
0x17 => [ 'ATR$C_RPRO', \&OpenVMS_2ByteValue ],
0x1D => [ 'ATR$C_JOURNAL', \&OpenVMS_DumpBytes ],
0x1F => [ 'ATR$C_ADDACLENT', \&OpenVMS_DumpBytes ],
} ;
out_V " CRC";
$len -= 4;
my $ix = 1;
while ($len)
{
my ($data, $tag) = read_v();
my $tagname = 'Unknown Tag';
my $decoder = undef;
if ($openVMS_tags->{$tag})
{
($tagname, $decoder) = @{ $openVMS_tags->{$tag} } ;
}
out2 $data, "Tag #$ix", Value_v($tag) . " '" . $tagname . "'" ;
my $size = out_v " Size";
if (defined $decoder)
{
$decoder->($ix, $tag, $size) ;
}
else
{
outSomeData($size, " Attribute");
}
++ $ix;
$len -= $size + 2 + 2;
}
}
sub getT
{
my $time = shift ;
if ($opt_utc)
{ return scalar gmtime($time) // 'Unknown'}
else
{ return scalar localtime($time) // 'Unknown' }
}
sub getTime
{
my $time = shift ;
return "'Invalid Date or Time'"
if ! defined $time;
return "'" . getT($time) . "'";
}
bin/zipdetails view on Meta::CPAN
return ()
if ! defined $offset;
$fh->seek($offset, SEEK_SET) ;
# Now walk the Central Directory Records
my $buffer ;
my $cdIndex = 0;
my $cdEntryOffset = 0;
while ($fh->read($buffer, ZIP_CD_FILENAME_OFFSET) == ZIP_CD_FILENAME_OFFSET &&
unpack("V", $buffer) == ZIP_CENTRAL_HDR_SIG) {
my $startHeader = $fh->tell() - ZIP_CD_FILENAME_OFFSET;
my $cdEntryOffset = $fh->tell() - ZIP_CD_FILENAME_OFFSET;
$HeaderOffsetIndex->addOffsetNoPrefix($cdEntryOffset, ZIP_CENTRAL_HDR_SIG) ;
++ $cdIndex ;
my $extractVer = unpack("v", substr($buffer, 6, 1));
my $gpFlag = unpack("v", substr($buffer, 8, 2));
my $lastMod = unpack("V", substr($buffer, 10, 4));
my $crc = unpack("V", substr($buffer, 16, 4));
my $compressedSize = unpack("V", substr($buffer, 20, 4));
my $uncompressedSize = unpack("V", substr($buffer, 24, 4));
my $filename_length = unpack("v", substr($buffer, 28, 2));
my $extra_length = unpack("v", substr($buffer, 30, 2));
my $comment_length = unpack("v", substr($buffer, 32, 2));
my $diskNumber = unpack("v", substr($buffer, 34, 2));
my $locHeaderOffset = unpack("V", substr($buffer, 42, 4));
my $cdZip64 = 0;
my $zip64Sizes = 0;
if (! full32 $locHeaderOffset)
{
# Check for corrupt offset
# 1. pointing paset EOF
# 2. offset points forward in the file
# 3. value at offset is not a CD record signature
my $commonMessage = "'Local Header Offset' field in '" . Signatures::name(ZIP_CENTRAL_HDR_SIG) . "' is invalid";
checkOffsetValue($locHeaderOffset, $startHeader, 0, $commonMessage,
$startHeader + CentralDirectoryEntry::Offset_RelativeOffsetToLocal(),
ZIP_LOCAL_HDR_SIG, 1) ;
}
$fh->read(my $filename, $filename_length) ;
my $cdEntry = CentralDirectoryEntry->new();
$cdEntry->centralHeaderOffset($startHeader) ;
$cdEntry->localHeaderOffset($locHeaderOffset) ;
$cdEntry->compressedSize($compressedSize) ;
$cdEntry->uncompressedSize($uncompressedSize) ;
$cdEntry->extractVersion($extractVer);
$cdEntry->generalPurposeFlags($gpFlag);
$cdEntry->filename($filename) ;
$cdEntry->lastModDateTime($lastMod);
$cdEntry->languageEncodingFlag($gpFlag & ZIP_GP_FLAG_LANGUAGE_ENCODING) ;
$cdEntry->diskNumber($diskNumber) ;
$cdEntry->crc32($crc) ;
$cdEntry->zip64ExtraPresent($cdZip64) ;
$cdEntry->std_localHeaderOffset($locHeaderOffset) ;
$cdEntry->std_compressedSize($compressedSize) ;
$cdEntry->std_uncompressedSize($uncompressedSize) ;
$cdEntry->std_diskNumber($diskNumber) ;
if ($extra_length)
{
$fh->read(my $extraField, $extra_length) ;
# Check for Zip64
my $zip64Extended = findID(0x0001, $extraField);
if ($zip64Extended)
{
$cdZip64 = 1;
walk_Zip64_in_CD(1, $zip64Extended, $cdEntry, 0);
}
}
$cdEntry->offsetStart($startHeader) ;
$cdEntry->offsetEnd($FH->tell() - 1);
# don't call addEntry until after the extra fields have been scanned
# the localheader offset value may be updated in th ezip64 extra field.
$CentralDirectory->addEntry($cdEntry);
$HeaderOffsetIndex->addOffset($cdEntry->localHeaderOffset, ZIP_LOCAL_HDR_SIG) ;
skip($fh, $comment_length ) ;
}
$FH->seek($fh->tell() - ZIP_CD_FILENAME_OFFSET, SEEK_SET);
# Check for Digital Signature
$HeaderOffsetIndex->addOffset($fh->tell() - 4, ZIP_DIGITAL_SIGNATURE_SIG)
if $fh->read($buffer, 4) == 4 &&
unpack("V", $buffer) == ZIP_DIGITAL_SIGNATURE_SIG ;
$CentralDirectory->sortByLocalOffset();
$HeaderOffsetIndex->sortOffsets();
$fh->seek($here, SEEK_SET) ;
}
use constant ZIP64_END_CENTRAL_LOC_HDR_SIZE => 20;
use constant ZIP64_END_CENTRAL_REC_HDR_MIN_SIZE => 56;
sub offsetFromZip64
{
my $fh = shift ;
my $here = shift;
my $eocdSize = shift;
#### Zip64 end of central directory locator
bin/zipdetails view on Meta::CPAN
}
}
}
{
package BaseEntry ;
sub new
{
my $class = shift ;
state $index = 0;
my %fields = (
'index' => $index ++,
'zip64' => 0,
'offsetStart' => 0,
'offsetEnd' => 0,
'inCentralDir' => 0,
'encapsulated' => 0, # enclosed in outer zip
'childrenCount' => 0, # this entry is a zip with enclosed children
'streamed' => 0,
'languageEncodingFlag' => 0,
'entryType' => 0,
) ;
my $self = bless {}, $class;
FieldsAndAccessors::Add($class, $self, \%fields) ;
return $self;
}
sub increment_childrenCount
{
my $self = shift;
$self->{childrenCount} ++;
}
}
{
package LocalCentralEntryBase ;
use parent -norequire , 'BaseEntry' ;
sub new
{
my $class = shift ;
my $self = $class->SUPER::new();
my %fields = (
# fields from the header
'centralHeaderOffset' => 0,
'localHeaderOffset' => 0,
'extractVersion' => 0,
'generalPurposeFlags' => 0,
'compressedMethod' => 0,
'lastModDateTime' => 0,
'crc32' => 0,
'compressedSize' => 0,
'uncompressedSize' => 0,
'filename' => '',
'outputFilename' => '',
# inferred data
# 'InCentralDir' => 0,
# 'zip64' => 0,
'zip64ExtraPresent' => 0,
'zip64SizesPresent' => 0,
'payloadOffset' => 0,
# zip64 extra
'zip64_compressedSize' => undef,
'zip64_uncompressedSize' => undef,
'zip64_localHeaderOffset' => undef,
'zip64_diskNumber' => undef,
'zip64_diskNumberPresent' => 0,
# Values direct from the header before merging any Zip64 values
'std_compressedSize' => undef,
'std_uncompressedSize' => undef,
'std_localHeaderOffset' => undef,
'std_diskNumber' => undef,
# AES
'aesStrength' => 0,
'aesValid' => 0,
# Minizip CD encryption
'minizip_secure' => 0,
) ;
FieldsAndAccessors::Add($class, $self, \%fields) ;
return $self;
}
}
{
package Zip64EndCentralHeaderEntry ;
use parent -norequire , 'LocalCentralEntryBase' ;
sub new
{
my $class = shift ;
my $self = $class->SUPER::new();
my %fields = (
'inCentralDir' => 1,
) ;
FieldsAndAccessors::Add($class, $self, \%fields) ;
return $self;
( run in 3.014 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )