Преглед изворни кода

Fix resave aligned archive

Ne-Lexa пре 8 година
родитељ
комит
ba2e314ca2

+ 11 - 7
src/PhpZip/Stream/ZipInputStream.php

@@ -481,9 +481,11 @@ class ZipInputStream implements ZipInputStreamInterface
         $pos = PHP_INT_SIZE === 4 ? sprintf('%u', $pos) : $pos;
         $pos = $this->mapper->map($pos);
 
-        $extraLength = strlen($entry->getExtra());
         $nameLength = strlen($entry->getName());
 
+        fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET);
+        $extraLength = unpack('v', fread($this->in, 2))[1];
+
         $length = ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $extraLength + $nameLength;
 
         $padding = 0;
@@ -505,7 +507,7 @@ class ZipInputStream implements ZipInputStreamInterface
         } else {
             stream_copy_to_stream($this->in, $out->getStream(), $length);
         }
-        $this->copyEntryData($entry, $out);
+        stream_copy_to_stream($this->in, $out->getStream(), $entry->getCompressedSize());
         if ($entry->getGeneralPurposeBitFlag(ZipEntry::GPBF_DATA_DESCRIPTOR)) {
             $length = 12;
             if ($entry->isZip64ExtensionsRequired()) {
@@ -524,11 +526,13 @@ class ZipInputStream implements ZipInputStreamInterface
         $offset = $entry->getOffset();
         $offset = PHP_INT_SIZE === 4 ? sprintf('%u', $offset) : $offset;
         $offset = $this->mapper->map($offset);
-        $position = $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN +
-            strlen($entry->getName()) + strlen($entry->getExtra());
-        $length = $entry->getCompressedSize();
-        fseek($this->in, $position, SEEK_SET);
-        stream_copy_to_stream($this->in, $out->getStream(), $length);
+        $nameLength = strlen($entry->getName());
+
+        fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET);
+        $extraLength = unpack('v', fread($this->in, 2))[1];
+
+        fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $nameLength + $extraLength, SEEK_SET);
+        stream_copy_to_stream($this->in, $out->getStream(), $entry->getCompressedSize());
     }
 
     public function __destruct()

+ 157 - 0
tests/PhpZip/ZipAlignTest.php

@@ -0,0 +1,157 @@
+<?php
+
+namespace PhpZip;
+
+use PhpZip\Util\CryptoUtil;
+
+/**
+ * Test ZipAlign
+ */
+class ZipAlignTest extends ZipTestCase
+{
+    public function testApkAlignedAndReSave()
+    {
+        $filename = __DIR__ . '/resources/test.apk';
+
+        self::assertCorrectZipArchive($filename);
+        self::doZipAlignVerify($this->outputFilename);
+
+        $zipFile = new ZipFile();
+        $zipFile->openFile($filename);
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+        self::doZipAlignVerify($this->outputFilename);
+    }
+
+    public function testApkAlignedAndSetZipAlignAndReSave()
+    {
+        $filename = __DIR__ . '/resources/test.apk';
+
+        self::assertCorrectZipArchive($filename);
+        self::doZipAlignVerify($this->outputFilename);
+
+        $zipFile = new ZipFile();
+        $zipFile->openFile($filename);
+        $zipFile->setZipAlign(4);
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+        self::doZipAlignVerify($this->outputFilename);
+    }
+
+    /**
+     * Test zip alignment.
+     */
+    public function testZipAlignSourceZip()
+    {
+        $zipFile = new ZipFile();
+        for ($i = 0; $i < 100; $i++) {
+            $zipFile->addFromString(
+                'entry' . $i . '.txt',
+                CryptoUtil::randomBytes(mt_rand(100, 4096)),
+                ZipFileInterface::METHOD_STORED
+            );
+        }
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+
+        $result = self::doZipAlignVerify($this->outputFilename);
+        if ($result === null) {
+            return;
+        } // zip align not installed
+
+        // check not zip align
+        self::assertFalse($result);
+
+        $zipFile->openFile($this->outputFilename);
+        $zipFile->setZipAlign(4);
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+
+        $result = self::doZipAlignVerify($this->outputFilename, true);
+        self::assertNotNull($result);
+
+        // check zip align
+        self::assertTrue($result);
+    }
+
+    public function testZipAlignNewFiles()
+    {
+        $zipFile = new ZipFile();
+        for ($i = 0; $i < 100; $i++) {
+            $zipFile->addFromString(
+                'entry' . $i . '.txt',
+                CryptoUtil::randomBytes(mt_rand(100, 4096)),
+                ZipFileInterface::METHOD_STORED
+            );
+        }
+        $zipFile->setZipAlign(4);
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+
+        $result = self::doZipAlignVerify($this->outputFilename);
+        if ($result === null) {
+            return;
+        } // zip align not installed
+        // check not zip align
+        self::assertTrue($result);
+    }
+
+    public function testZipAlignFromModifiedZipArchive()
+    {
+        $zipFile = new ZipFile();
+        for ($i = 0; $i < 100; $i++) {
+            $zipFile->addFromString(
+                'entry' . $i . '.txt',
+                CryptoUtil::randomBytes(mt_rand(100, 4096)),
+                ZipFileInterface::METHOD_STORED
+            );
+        }
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+
+        $result = self::doZipAlignVerify($this->outputFilename);
+        if ($result === null) {
+            return;
+        } // zip align not installed
+
+        // check not zip align
+        self::assertFalse($result);
+
+        $zipFile->openFile($this->outputFilename);
+        $zipFile->deleteFromRegex("~entry2[\d]+\.txt$~s");
+        for ($i = 0; $i < 100; $i++) {
+            $isStored = (bool)mt_rand(0, 1);
+
+            $zipFile->addFromString(
+                'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt',
+                CryptoUtil::randomBytes(mt_rand(100, 4096)),
+                $isStored ?
+                    ZipFileInterface::METHOD_STORED :
+                    ZipFileInterface::METHOD_DEFLATED
+            );
+        }
+        $zipFile->setZipAlign(4);
+        $zipFile->saveAsFile($this->outputFilename);
+        $zipFile->close();
+
+        self::assertCorrectZipArchive($this->outputFilename);
+
+        $result = self::doZipAlignVerify($this->outputFilename, true);
+        self::assertNotNull($result);
+
+        // check zip align
+        self::assertTrue($result);
+    }
+}

+ 10 - 115
tests/PhpZip/ZipFileTest.php

@@ -404,7 +404,11 @@ class ZipFileTest extends ZipTestCase
         $zipFile->openFile($this->outputFilename);
         $zipFile->rename($oldName, $newName);
         $zipFile->addFromString('file1.txt', 'content');
-        $zipFile->rename('file1.txt', 'file2.txt');
+        $zipFile->addFromString('file2.txt', 'content');
+        $zipFile->addFromString('file3.txt', 'content');
+        $zipFile->rename('file1.txt', 'file_long_name.txt');
+        $zipFile->rename('file2.txt', 'file4.txt');
+        $zipFile->rename('file3.txt', 'fi.txt');
         $zipFile->saveAsFile($this->outputFilename);
         $zipFile->close();
 
@@ -414,7 +418,11 @@ class ZipFileTest extends ZipTestCase
         self::assertFalse(isset($zipFile[$oldName]));
         self::assertTrue(isset($zipFile[$newName]));
         self::assertFalse(isset($zipFile['file1.txt']));
-        self::assertTrue(isset($zipFile['file2.txt']));
+        self::assertFalse(isset($zipFile['file2.txt']));
+        self::assertFalse(isset($zipFile['file3.txt']));
+        self::assertTrue(isset($zipFile['file_long_name.txt']));
+        self::assertTrue(isset($zipFile['file4.txt']));
+        self::assertTrue(isset($zipFile['fi.txt']));
         $zipFile->close();
     }
 
@@ -1737,119 +1745,6 @@ class ZipFileTest extends ZipTestCase
         $zipFile->rewrite();
     }
 
-    /**
-     * Test zip alignment.
-     */
-    public function testZipAlignSourceZip()
-    {
-        $zipFile = new ZipFile();
-        for ($i = 0; $i < 100; $i++) {
-            $zipFile->addFromString(
-                'entry' . $i . '.txt',
-                CryptoUtil::randomBytes(mt_rand(100, 4096)),
-                ZipFileInterface::METHOD_STORED
-            );
-        }
-        $zipFile->saveAsFile($this->outputFilename);
-        $zipFile->close();
-
-        self::assertCorrectZipArchive($this->outputFilename);
-
-        $result = self::doZipAlignVerify($this->outputFilename);
-        if ($result === null) {
-            return;
-        } // zip align not installed
-
-        // check not zip align
-        self::assertFalse($result);
-
-        $zipFile->openFile($this->outputFilename);
-        $zipFile->setZipAlign(4);
-        $zipFile->saveAsFile($this->outputFilename);
-        $zipFile->close();
-
-        self::assertCorrectZipArchive($this->outputFilename);
-
-        $result = self::doZipAlignVerify($this->outputFilename, true);
-        self::assertNotNull($result);
-
-        // check zip align
-        self::assertTrue($result);
-    }
-
-    public function testZipAlignNewFiles()
-    {
-        $zipFile = new ZipFile();
-        for ($i = 0; $i < 100; $i++) {
-            $zipFile->addFromString(
-                'entry' . $i . '.txt',
-                CryptoUtil::randomBytes(mt_rand(100, 4096)),
-                ZipFileInterface::METHOD_STORED
-            );
-        }
-        $zipFile->setZipAlign(4);
-        $zipFile->saveAsFile($this->outputFilename);
-        $zipFile->close();
-
-        self::assertCorrectZipArchive($this->outputFilename);
-
-        $result = self::doZipAlignVerify($this->outputFilename);
-        if ($result === null) {
-            return;
-        } // zip align not installed
-        // check not zip align
-        self::assertTrue($result);
-    }
-
-    public function testZipAlignFromModifiedZipArchive()
-    {
-        $zipFile = new ZipFile();
-        for ($i = 0; $i < 100; $i++) {
-            $zipFile->addFromString(
-                'entry' . $i . '.txt',
-                CryptoUtil::randomBytes(mt_rand(100, 4096)),
-                ZipFileInterface::METHOD_STORED
-            );
-        }
-        $zipFile->saveAsFile($this->outputFilename);
-        $zipFile->close();
-
-        self::assertCorrectZipArchive($this->outputFilename);
-
-        $result = self::doZipAlignVerify($this->outputFilename);
-        if ($result === null) {
-            return;
-        } // zip align not installed
-
-        // check not zip align
-        self::assertFalse($result);
-
-        $zipFile->openFile($this->outputFilename);
-        $zipFile->deleteFromRegex("~entry2[\d]+\.txt$~s");
-        for ($i = 0; $i < 100; $i++) {
-            $isStored = (bool)mt_rand(0, 1);
-
-            $zipFile->addFromString(
-                'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt',
-                CryptoUtil::randomBytes(mt_rand(100, 4096)),
-                $isStored ?
-                    ZipFileInterface::METHOD_STORED :
-                    ZipFileInterface::METHOD_DEFLATED
-            );
-        }
-        $zipFile->setZipAlign(4);
-        $zipFile->saveAsFile($this->outputFilename);
-        $zipFile->close();
-
-        self::assertCorrectZipArchive($this->outputFilename);
-
-        $result = self::doZipAlignVerify($this->outputFilename, true);
-        self::assertNotNull($result);
-
-        // check zip align
-        self::assertTrue($result);
-    }
-
     public function testFilename0()
     {
         $zipFile = new ZipFile();

BIN
tests/PhpZip/resources/test.apk