You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by pe...@apache.org on 2020/09/07 06:40:08 UTC

[commons-compress] branch master updated: COMPRESS-550 : add writePreamble to ZipArchiveInputStream

This is an automated email from the ASF dual-hosted git repository.

peterlee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git


The following commit(s) were added to refs/heads/master by this push:
     new a40c53d  COMPRESS-550 : add writePreamble to ZipArchiveInputStream
a40c53d is described below

commit a40c53d1494d71d09f57880f1a333445ddf4c535
Author: PeterAlfredLee <pe...@gmail.com>
AuthorDate: Tue Aug 18 15:22:39 2020 +0800

    COMPRESS-550 : add writePreamble to ZipArchiveInputStream
    
    Add writePreamble to ZipArchiveInputStream. This is used to create
    self-extracting zips.
---
 .../archivers/zip/ZipArchiveOutputStream.java      | 29 ++++++++
 .../compress/archivers/zip/ZipFileTest.java        | 80 ++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
index e145e6d..3d63bf2 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
@@ -1005,6 +1005,35 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
     }
 
     /**
+     * Write preamble data. For most of time, this is used to
+     * make self-extracting zips.
+     *
+     * @param preamble data to write
+     * @throws IOException if an entry already exists
+     * @since 1.21
+     */
+    public void writePreamble(final byte[] preamble) throws IOException {
+        writePreamble(preamble, 0, preamble.length);
+    }
+
+    /**
+     * Write preamble data. For most of time, this is used to
+     * make self-extracting zips.
+     *
+     * @param preamble data to write
+     * @param offset   the start offset in the data
+     * @param length   the number of bytes to write
+     * @throws IOException if an entry already exists
+     * @since 1.21
+     */
+    public void writePreamble(final byte[] preamble, final int offset, final int length) throws IOException {
+        if (entry != null) {
+            throw new IllegalStateException("Preamble must be written before creating an entry");
+        }
+        this.streamCompressor.writeCounted(preamble, offset, length);
+    }
+
+    /**
      * Writes bytes to ZIP entry.
      * @param b the byte array to write
      * @param offset the start position to write from
diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
index c2b6485..1d43752 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
@@ -763,6 +763,86 @@ public class ZipFileTest {
         outputStream.setLevel(Deflater.BEST_COMPRESSION + 1);
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void throwsExceptionWhenWritingPreamble() throws IOException {
+        final ZipArchiveOutputStream outputStream = new ZipArchiveOutputStream(new ByteArrayOutputStream());
+        outputStream.putArchiveEntry(new ZipArchiveEntry());
+        outputStream.writePreamble(new byte[0]);
+    }
+
+    @Test
+    public void testSelfExtractingZipUsingUnzipsfx() throws IOException, InterruptedException {
+        final File unzipsfx = new File("/usr/bin/unzipsfx");
+        if (!unzipsfx.exists()) {
+            return;
+        }
+
+        final File testZip = File.createTempFile("commons-compress-selfExtractZipTest", ".zip");
+        testZip.deleteOnExit();
+
+        final String testEntryName = "test_self_extract_zip/foo";
+        final File extractedFile = new File(testZip.getParentFile(), testEntryName);
+        extractedFile.deleteOnExit();
+
+        OutputStream outputStream = null;
+        InputStream inputStream = null;
+        final byte[] testData = new byte[]{1, 2, 3, 4};
+        byte[] buffer = new byte[512];
+        int bytesRead;
+        try (InputStream unzipsfxInputStream = new FileInputStream(unzipsfx)) {
+            outputStream = new FileOutputStream(testZip);
+            final ZipArchiveOutputStream zo = new ZipArchiveOutputStream(outputStream);
+
+            while ((bytesRead = unzipsfxInputStream.read(buffer)) > 0) {
+                zo.writePreamble(buffer, 0, bytesRead);
+            }
+
+            ZipArchiveEntry ze = new ZipArchiveEntry(testEntryName);
+            ze.setMethod(ZipEntry.STORED);
+            ze.setSize(4);
+            ze.setCrc(0xb63cfbcdl);
+            zo.putArchiveEntry(ze);
+            zo.write(testData);
+            zo.closeArchiveEntry();
+            zo.close();
+            outputStream.close();
+            outputStream = null;
+
+            final ProcessBuilder pbChmod = new ProcessBuilder("chmod", "+x", testZip.getPath());
+            pbChmod.redirectErrorStream(true);
+            final Process processChmod = pbChmod.start();
+            assertEquals(new String(IOUtils.toByteArray(processChmod.getInputStream())), 0, processChmod.waitFor());
+
+            final ProcessBuilder pb = new ProcessBuilder(testZip.getPath());
+            pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
+            pb.directory(testZip.getParentFile());
+            pb.redirectErrorStream(true);
+            final Process process = pb.start();
+            assertEquals(new String(IOUtils.toByteArray(process.getInputStream())), 0, process.waitFor());
+
+            if (!extractedFile.exists()) {
+                // fail if extracted file does not exist
+                fail("Can not find the extracted file");
+            }
+
+            inputStream = new FileInputStream(extractedFile);
+            bytesRead = IOUtils.readFully(inputStream, buffer);
+            assertEquals(testData.length, bytesRead);
+            assertArrayEquals(testData, Arrays.copyOfRange(buffer, 0, bytesRead));
+        } finally {
+            if (outputStream != null) {
+                outputStream.close();
+            }
+            if (inputStream != null) {
+                inputStream.close();
+            }
+
+            testZip.delete();
+            extractedFile.delete();
+            extractedFile.getParentFile().delete();
+        }
+    }
+
     private void multiByteReadConsistentlyReturnsMinusOneAtEof(final File file) throws Exception {
         final byte[] buf = new byte[2];
         try (ZipFile archive = new ZipFile(file)) {