@@ -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