Skip to content

Commit

Permalink
Add data descriptor header
Browse files Browse the repository at this point in the history
As specified in 4.3.9.3 and 4.3.9.4

4.3.9.3 Although not originally assigned a signature, the value
      0x08074b50 has commonly been adopted as a signature value
      for the data descriptor record.  Implementers should be
      aware that ZIP files may be encountered with or without this
      signature marking data descriptors and SHOULD account for
      either case when reading ZIP files to ensure compatibility.

4.3.9.4 When writing ZIP files, implementors SHOULD include the
      signature value marking the data descriptor record.  When
      the signature is used, the fields currently defined for
      the data descriptor record will immediately follow the
      signature.

Signed-off-by: Roeland Jago Douma <[email protected]>
  • Loading branch information
rullzer committed Mar 8, 2018
1 parent 96813f8 commit a910389
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/ZipStreamer.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class ZipStreamer {
const VERSION = "1.0";

const ZIP_LOCAL_FILE_HEADER = 0x04034b50; // local file header signature
const ZIP_DATA_DESCRIPTOR_HEADER = 0x08074b50; //data descriptor header signature
const ZIP_CENTRAL_FILE_HEADER = 0x02014b50; // central file header signature
const ZIP_END_OF_CENTRAL_DIRECTORY = 0x06054b50; // end of central directory record
const ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50; //zip64 end of central directory record
Expand Down Expand Up @@ -431,16 +432,17 @@ private function buildLocalFileHeader($filePath, $timestamp, $gpFlags,

private function addDataDescriptor($dataLength, $gzLength, $dataCRC32) {
if ($this->zip64) {
$length = 20;
$length = 24;
$packedGzLength = pack64le($gzLength);
$packedDataLength = pack64le($dataLength);
} else {
$length = 12;
$length = 16;
$packedGzLength = pack32le($gzLength->getLoBytes());
$packedDataLength = pack32le($dataLength->getLoBytes());
}

$this->write(''
. pack32le(self::ZIP_DATA_DESCRIPTOR_HEADER) // data descriptor header signature 4 bytes (0x08074b50)
. pack32le($dataCRC32) // crc-32 4 bytes
. $packedGzLength // compressed size 4/8 bytes (depending on zip64 enabled)
. $packedDataLength // uncompressed size 4/8 bytes (depending on zip64 enabled)
Expand Down
17 changes: 14 additions & 3 deletions test/ZipComponents.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,9 @@ public function readFromString($str, $pos, $size = -1) {
}
if (GPFLAGS::ADD & $this->lfh->gpFlags) {
if (is_null($this->lfh->z64Ext)) {
$ddLength = 12;
$ddLength = 16;
} else {
$ddLength = 20;
$ddLength = 24;
}
$this->dd = DataDescriptor::constructFromString($str, $pos, $ddLength);
$pos = $this->dd->end + 1;
Expand Down Expand Up @@ -568,6 +568,7 @@ public function readFromString($str, $pos, $size = -1) {
* @codeCoverageIgnore
*/
class DataDescriptor extends zipRecord {
protected static $MAGIC = 0x08074b50; // data descriptor header signature
protected static $shortName = "DD";
public $dataCRC32;
public $sizeCompressed;
Expand All @@ -584,13 +585,23 @@ public function __toString() {
}

public static function constructFromString($str, $offset = 0, $size = -1) {
$ddheadPos = strpos($str, static::getMagicBytes(), $offset);
if (self::$unitTest) {
self::$unitTest->assertFalse(False === $ddheadPos, "data descriptor header missing");
self::$unitTest->assertEquals($offset, $ddheadPos, "garbage before data descriptor header");
}

return static::__constructFromString($str, $offset, $size);
}

public function readFromString($str, $pos, $size = -1) {
$this->begin = $pos;
$magic = readstr($str, $pos, 4);
if (static::getMagicBytes() != $magic) {
throw new ParseException("invalid magic");
}
$this->dataCRC32 = (int) unpack32le(readstr($str, $pos, 4));
if (20 == $size) {
if (24 == $size) {
$this->sizeCompressed = unpack64le(readstr($str, $pos, 8));
$this->size = unpack64le(readstr($str, $pos, 8));
} else {
Expand Down
2 changes: 1 addition & 1 deletion test/integration/UnpackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function test7zip() {
$fullOutput = implode("\n", $output);
$this->assertEquals($output[1], '7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21', $fullOutput);
$this->assertEquals(0, $return_var, $fullOutput);
$this->assertTrue(in_array('1 file, 939 bytes (1 KiB)', $output), $fullOutput);
$this->assertTrue(in_array('1 file, 943 bytes (1 KiB)', $output), $fullOutput);
}

public function testUnzip() {
Expand Down

0 comments on commit a910389

Please sign in to comment.