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 ----------