A DESCRIPTION OF THE PROBLEM :
When ZipFile.getInputStream is called for a STORED entry, a ZipFile$ZipFileInputStream is returned. The method skip(long) of this class is not correctly handling negative values.
All (?) other implementations of InputStream either return 0 when the skip amount is <= 0, or throw an exception. However, ZipFileInputStream simply accepts the negative value, possibly even returning it as number of skipped bytes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the provided code
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either "0" is printed as skipped amount or an exception is thrown
ACTUAL -
"-100" is printed as number of skipped bytes
---------- BEGIN SOURCE ----------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
public class ZipFileInputStreamTest {
public static void main(String[] args) throws IOException {
Path tempFile = Files.createTempFile("zip-test", ".zip");
try {
Files.write(tempFile, createZipFileData());
try (ZipFile zipFile = new ZipFile(tempFile.toFile())) {
ZipEntry entry = zipFile.entries().nextElement();
InputStream entryIn = zipFile.getInputStream(entry);
long skipped = entryIn.skip(-100);
System.out.println("Skipped: " + skipped);
}
}
finally {
Files.delete(tempFile);
}
}
private static byte[] createZipFileData() {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(out);
try {
// STORED has to be used, DEFLATED would wrap stream inside ZipFileInflaterInputStream
// which prevents negative skip amounts
zipOut.setMethod(ZipEntry.STORED);
ZipEntry zipEntry = new ZipEntry("test");
byte[] data = new byte[] {'t', 'e', 's', 't'};
zipEntry.setSize(data.length);
CRC32 crc32 = new CRC32();
crc32.update(data);
zipEntry.setCrc(crc32.getValue());
zipOut.putNextEntry(zipEntry);
zipOut.write(data);
zipOut.finish();
}
catch (IOException ioException) {
throw new UncheckedIOException(ioException);
}
return out.toByteArray();
}
}
---------- END SOURCE ----------