Skip to content

Commit

Permalink
COMPRESS-550 : add writePreamble to ZipArchiveInputStream
Browse files Browse the repository at this point in the history
Add writePreamble to ZipArchiveInputStream. This is used to create
self-extracting zips.
  • Loading branch information
PeterAlfredLee committed Aug 24, 2020
1 parent 86bb35a commit 2f61221
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,35 @@ public boolean canWriteEntryData(final ArchiveEntry ae) {
return false;
}

/**
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,86 @@ public void testSetLevelTooBigForZipArchiveOutputStream() throws Exception {
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)) {
Expand Down

0 comments on commit 2f61221

Please sign in to comment.