import java.io.*;
import java.util.zip.*;

public class StoredCRC {
    public static void realMain(String[] args) throws Throwable {

        try {
            // Valid empty entry
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);
            ZipEntry ze = new ZipEntry("empty");
            ze.setMethod(ZipOutputStream.STORED);
            ze.setSize(0);
            CRC32 crc = new CRC32();
            crc.update(new byte[0]);
            ze.setCrc(crc.getValue());
            System.out.println("real crc: " + crc.getValue());
            zos.putNextEntry(ze);
            zos.close();

            // Verify valid read
            ZipInputStream zis = new ZipInputStream(
                    new ByteArrayInputStream(baos.toByteArray()));
            check(zis.getNextEntry() != null);
            check(zis.read() == -1); // Immediate EOF

            // Corrupt empty entry's CRC
            byte[] corrupted = baos.toByteArray();
            corrupted[14] ^= 1; // Toggle CRC byte
            zis = new ZipInputStream(new ByteArrayInputStream(corrupted));

            ze = zis.getNextEntry();
            check(ze != null);
            check(zis.read() == -1); // Read to EOF
            System.out.println(ze);
            System.out.println("Changed crc: " + ze.getCrc());
            System.out.println();
            try {
                zis.getNextEntry();
                zis.closeEntry();
                zis.close();
                fail("Empty entry: No CRC check for zero-length file");
            } catch (ZipException ex) {
                check(ex.getMessage().startsWith("invalid entry CRC (expected 0x"));
            }
        } catch (Throwable t) {
            unexpected(t);
        }

    }




    //--------------------- Infrastructure ---------------------------
    static volatile int passed = 0, failed = 0;
    static boolean pass() {passed++; return true;}
    static boolean fail() {failed++; Thread.dumpStack(); return false;}
    static boolean fail(String msg) {System.out.println(msg); return fail();}
    static void unexpected(Throwable t) {failed++; t.printStackTrace();}
    static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
    static boolean equal(Object x, Object y) {
        if (x == null ? y == null : x.equals(y)) return pass();
        else return fail(x + " not equal to " + y);}
    public static void main(String[] args) throws Throwable {
        try {realMain(args);} catch (Throwable t) {unexpected(t);}
        System.out.println("\nPassed = " + passed + " failed = " + failed);
        if (failed > 0) throw new AssertionError("Some tests failed");}
}
