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 all 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
40 changes: 37 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,49 @@ 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);
newEntry.setMethod(entry.getMethod());
switch (entry.getMethod()) {
case 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
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
count += filterOrInstrument(zipin, buffer, name, entryName);
final byte[] bytes = buffer.toByteArray();
newEntry.setSize(bytes.length);
newEntry.setCompressedSize(bytes.length);
newEntry.setCrc(crc(bytes));
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 static long crc(final byte[] data) {
final CRC32 crc = new CRC32();
crc.update(data);
return crc.getValue();
}

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/1018">#1018</a>).</li>
</ul>

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