Skip to content

Commit efc9b63

Browse files
committed
Merge code suggested from barracudanetworks#45
1 parent eef2876 commit efc9b63

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

src/ZipReader.php

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,18 @@ public function read($blockSize)
8787
yield $this->addCdrFile($file);
8888
}
8989

90-
yield $this->addCdrEofZip64();
91-
yield $this->addCdrEofLocatorZip64();
90+
$num = count($this->files);
91+
$num = $num > 0xFFFF ? 0xFFFF : $num;
92+
list($cdr_len_low, $cdr_len_high) = PackHelper::int64Split($this->cdr_len);
93+
list($cdr_ofs_low, $cdr_ofs_high) = PackHelper::int64Split($this->cdr_ofs);
94+
$cdr_len = $cdr_len_high ? 0xFFFFFFFF : $cdr_len_low;
95+
$cdr_ofs = $cdr_ofs_high ? 0xFFFFFFFF : $cdr_ofs_low;
96+
97+
if ($num == 0xFFFF || $cdr_len == 0xFFFFFFFF || $cdr_ofs == 0xFFFFFFFF) {
98+
yield $this->addCdrEofZip64();
99+
yield $this->addCdrEofLocatorZip64();
100+
}
101+
92102
yield $this->addCdrEof();
93103

94104
$this->clear();
@@ -131,7 +141,7 @@ private function sendFileHeader(ContentInterface $content, $method)
131141
// strip leading slashes from file name
132142
// (fixes bug in windows archive viewer)
133143
$name = preg_replace('/^\\/+/', '', $name);
134-
$extra = pack('vVVVV', 1, 0, 0, 0, 0);
144+
$extra = pack('vvVVVV', 1, 0x10, 0, 0, 0, 0);
135145

136146
// create dos timestamp
137147
$dts = PackHelper::dostime($content->getModifiedAt());
@@ -148,6 +158,9 @@ private function sendFileHeader(ContentInterface $content, $method)
148158
$genb |= 0x0800;
149159
}
150160

161+
$num = count($this->files);
162+
$num = $num > 0xFFFF ? 0xFFFF : $num;
163+
151164
// build file header
152165
$fields = [ // (from V.A of APPNOTE.TXT)
153166
['V', 0x04034b50], // local file header signature
@@ -275,9 +288,23 @@ private function addCdrFile(array $args)
275288

276289
// ZIP64, necessary for files over 4GB (incl. entire archive size)
277290
$extra_zip64 = '';
278-
$extra_zip64 .= pack('VV', $len_low, $len_high);
279-
$extra_zip64 .= pack('VV', $zlen_low, $zlen_high);
280-
$extra_zip64 .= pack('VV', $ofs_low, $ofs_high);
291+
if ($len == 0xFFFFFFFF) {
292+
$extra_zip64 .= pack('VV', $len_low, $len_high);
293+
}
294+
295+
if ($zlen == 0xFFFFFFFF) {
296+
$extra_zip64 .= pack('VV', $zlen_low, $zlen_high);
297+
}
298+
if ($ofs == 0xFFFFFFFF) {
299+
$extra_zip64 .= pack('VV', $ofs_low, $ofs_high);
300+
}
301+
302+
303+
if (!empty($extra_zip64)) {
304+
$extra = pack('vv', 1, strlen($extra_zip64)) . $extra_zip64;
305+
} else {
306+
$extra = '';
307+
}
281308

282309
$extra = pack('vv', 1, strlen($extra_zip64)) . $extra_zip64;
283310

@@ -295,15 +322,15 @@ private function addCdrFile(array $args)
295322
['v', $meth], // compresion method (deflate or store)
296323
['V', $dts], // dos timestamp
297324
['V', $crc], // crc32 of data
298-
['V', 0xFFFFFFFF], // compressed data length (zip64 - look in extra)
299-
['V', 0xFFFFFFFF], // uncompressed data length (zip64 - look in extra)
325+
['V', $zlen], // compressed data length (zip64 - look in extra)
326+
['V', $len], // uncompressed data length (zip64 - look in extra)
300327
['v', strlen($name)], // filename length
301328
['v', strlen($extra)], // extra data len
302329
['v', strlen($comment)], // file comment length
303330
['v', 0], // disk number start
304331
['v', 0], // internal file attributes
305332
['V', $file_attribute], // external file attributes, 0x10 for dir, 0x20 for file
306-
['V', 0xFFFFFFFF], // relative offset of local header (zip64 - look in extra)
333+
['V', $ofs], // relative offset of local header (zip64 - look in extra)
307334
];
308335

309336
// pack fields, then append name and comment
@@ -389,14 +416,22 @@ private function addCdrEofLocatorZip64()
389416
private function addCdrEof()
390417
{
391418
$comment = $this->archive->getComment();
419+
420+
$num = count($this->files);
421+
$num = $num > 0xFFFF ? 0xFFFF : $num;
422+
list($cdr_len_low, $cdr_len_high) = PackHelper::int64Split($this->cdr_len);
423+
list($cdr_ofs_low, $cdr_ofs_high) = PackHelper::int64Split($this->cdr_ofs);
424+
$cdr_len = $cdr_len_high ? 0xFFFFFFFF : $cdr_len_low;
425+
$cdr_ofs = $cdr_ofs_high ? 0xFFFFFFFF : $cdr_ofs_low;
426+
392427
$fields = [ // (from V,F of APPNOTE.TXT)
393428
['V', 0x06054b50], // end of central file header signature
394-
['v', 0xFFFF], // this disk number (0xFFFF to look in zip64 cdr)
395-
['v', 0xFFFF], // number of disk with cdr (0xFFFF to look in zip64 cdr)
396-
['v', 0xFFFF], // number of entries in the cdr on this disk (0xFFFF to look in zip64 cdr))
397-
['v', 0xFFFF], // number of entries in the cdr (0xFFFF to look in zip64 cdr)
398-
['V', 0xFFFFFFFF], // cdr size (0xFFFFFFFF to look in zip64 cdr)
399-
['V', 0xFFFFFFFF], // cdr offset (0xFFFFFFFF to look in zip64 cdr)
429+
['v', 0x0000], // this disk number (0xFFFF to look in zip64 cdr)
430+
['v', 0x0000], // number of disk with cdr (0xFFFF to look in zip64 cdr)
431+
['v', $num], // number of entries in the cdr on this disk (0xFFFF to look in zip64 cdr))
432+
['v', $num], // number of entries in the cdr (0xFFFF to look in zip64 cdr)
433+
['V', $cdr_len], // cdr size (0xFFFFFFFF to look in zip64 cdr)
434+
['V', $cdr_ofs], // cdr offset (0xFFFFFFFF to look in zip64 cdr)
400435
['v', strlen($comment)], // zip file comment length
401436
];
402437

0 commit comments

Comments
 (0)