Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve compression method when instrumenting zip entries #1018

Merged
merged 6 commits into from Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -26,6 +26,7 @@
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
Expand Down Expand Up @@ -250,18 +251,38 @@ public void testInstrumentAll_Class() throws IOException {
public void testInstrumentAll_Zip() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ZipOutputStream zipout = new ZipOutputStream(buffer);
zipout.putNextEntry(new ZipEntry("Test.class"));

// Compressed Entry
ZipEntry entry = new ZipEntry("TestCompressed.class");
entry.setMethod(ZipEntry.DEFLATED);
zipout.putNextEntry(entry);
zipout.write(TargetLoader.getClassDataAsBytes(getClass()));

// Uncompressed Entry
entry = new ZipEntry("TestUncompressed.class");
entry.setMethod(ZipEntry.STORED);
entry.setSize(TargetLoader.getClassDataAsBytes(getClass()).length);
CRC32 crc = new CRC32();
crc.update(TargetLoader.getClassDataAsBytes(getClass()));
entry.setCrc(crc.getValue());
zipout.putNextEntry(entry);
zipout.write(TargetLoader.getClassDataAsBytes(getClass()));

zipout.finish();
ByteArrayOutputStream out = new ByteArrayOutputStream();

int count = instrumenter.instrumentAll(
new ByteArrayInputStream(buffer.toByteArray()), out, "Test");

assertEquals(1, count);
assertEquals(2, count);
ZipInputStream zipin = new ZipInputStream(
new ByteArrayInputStream(out.toByteArray()));
assertEquals("Test.class", zipin.getNextEntry().getName());
entry = zipin.getNextEntry();
assertEquals("TestCompressed.class", entry.getName());
assertEquals(ZipEntry.DEFLATED, entry.getMethod());
entry = zipin.getNextEntry();
assertEquals("TestUncompressed.class", entry.getName());
assertEquals(ZipEntry.STORED, entry.getMethod());
assertNull(zipin.getNextEntry());
}

Expand Down
37 changes: 34 additions & 3 deletions org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
Expand Up @@ -16,6 +16,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.CRC32;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
Expand Down Expand Up @@ -216,16 +217,46 @@ private int instrumentZip(final InputStream input,
continue;
}

zipout.putNextEntry(new ZipEntry(entryName));
if (!signatureRemover.filterEntry(entryName, zipin, zipout)) {
count += instrumentAll(zipin, zipout, name + "@" + entryName);
final ZipEntry newEntry = new ZipEntry(entryName);
switch (entry.getMethod()) {
case ZipEntry.DEFLATED:
newEntry.setMethod(ZipEntry.DEFLATED);
zipout.putNextEntry(newEntry);
count += filterOrInstrument(zipin, zipout, name, entryName);
break;
case ZipEntry.STORED:
// Uncompressed entries must be processed in-memory to calculate
// mandatory entry size and CRC
newEntry.setMethod(ZipEntry.STORED);
Godin marked this conversation as resolved.
Show resolved Hide resolved
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
count += filterOrInstrument(zipin, buffer, name, entryName);
final byte[] bytes = buffer.toByteArray();
newEntry.setSize(bytes.length);
newEntry.setCompressedSize(bytes.length);
final CRC32 crc = new CRC32();
crc.update(bytes);
newEntry.setCrc(crc.getValue());
zipout.putNextEntry(newEntry);
zipout.write(bytes);
break;
default:
throw new AssertionError(entry.getMethod());
}
zipout.closeEntry();
}
zipout.finish();
return count;
}

private int filterOrInstrument(final InputStream in, final OutputStream out,
final String name, final String entryName) throws IOException {
if (signatureRemover.filterEntry(entryName, in, out)) {
return 0;
} else {
return instrumentAll(in, out, name + "@" + entryName);
}
}

private ZipEntry nextEntry(final ZipInputStream input,
final String location) throws IOException {
try {
Expand Down
7 changes: 7 additions & 0 deletions org.jacoco.doc/docroot/doc/changes.html
Expand Up @@ -37,6 +37,13 @@ <h3>New Features</h3>
(GitHub <a href="https://github.com/jacoco/jacoco/issues/1016">#1016</a>).</li>
</ul>

<h3>Fixed bugs</h3>
<ul>
<li>Compression method of zip entries is now preserved when instrumenting archives.
This allows to use JaCoCo with frameworks that expect uncompressed entries
(GitHub <a href="https://github.com/jacoco/jacoco/issues/1004">#1004</a>).</li>
marchof marked this conversation as resolved.
Show resolved Hide resolved
</ul>

<h3>Non-functional Changes</h3>
<ul>
<li>Support for Pack200 was removed in JDK 14. JaCoCo will now throw a detailed
Expand Down