# HG changeset patch # User redestad # Date 1555417135 -7200 # Tue Apr 16 14:18:55 2019 +0200 # Node ID 15f6175fdafd59859efa471d5727940dbf051a30 # Parent ba51515b64e59be3fe848525b3ebd9d68e13aebf imported patch def diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -1187,18 +1187,23 @@ return 0; long written = 0; - try (OutputStream os2 = e.method == METHOD_STORED ? - new EntryOutputStreamCRC32(e, os) : new EntryOutputStreamDef(e, os)) { - if (e.bytes != null) { // in-memory - os2.write(e.bytes, 0, e.bytes.length); - } else if (e.file != null) { // tmp file - if (e.type == Entry.NEW || e.type == Entry.FILECH) { - try (InputStream is = Files.newInputStream(e.file)) { - is.transferTo(os2); + if (e.bytes != null && e.crc != 0) { + // precompressed entry, write directly to output stream + os.write(e.bytes, 0, e.bytes.length); + } else { + try (OutputStream os2 = e.method == METHOD_STORED ? + new EntryOutputStreamCRC32(e, os) : new EntryOutputStreamDef(e, os)) { + if (e.bytes != null) { // in-memory + os2.write(e.bytes, 0, e.bytes.length); + } else if (e.file != null) { // tmp file + if (e.type == Entry.NEW || e.type == Entry.FILECH) { + try (InputStream is = Files.newInputStream(e.file)) { + is.transferTo(os2); + } } + Files.delete(e.file); + tmppaths.remove(e.file); } - Files.delete(e.file); - tmppaths.remove(e.file); } } written += e.csize; @@ -1327,6 +1332,10 @@ e.file = getTempPathForEntry(null); os = Files.newOutputStream(e.file, WRITE); } else { + if (defaultMethod == METHOD_DEFLATED) { + return new DeflatingByteArrayEntryOutputStream(e, + new ByteArrayOutputStream((e.size > 0)? (int)e.size : 8192)); + } os = new ByteArrayOutputStream((e.size > 0)? (int)e.size : 8192); } return new EntryOutputStream(e, os); @@ -1370,6 +1379,47 @@ } } + // Output stream returned when writing "deflated" entries into memory, + // to enable eager (possibly parallel) deflation and reduce memory required. + private class DeflatingByteArrayEntryOutputStream extends DeflaterOutputStream { + private Entry e; + private CRC32 crc; + private boolean isClosed; + + DeflatingByteArrayEntryOutputStream(Entry e, ByteArrayOutputStream os) throws IOException { + super(os, getDeflater()); + this.e = Objects.requireNonNull(e, "Zip entry is null"); + this.crc = new CRC32(); + } + + @Override + public synchronized void write(int b) throws IOException { + super.write(b); + crc.update(b); + } + + @Override + public synchronized void write(byte b[], int off, int len) + throws IOException { + super.write(b, off, len); + crc.update(b, off, len); + } + + @Override + public synchronized void close() throws IOException { + if (isClosed) + return; + isClosed = true; + finish(); + e.size = def.getBytesRead(); + e.csize = def.getBytesWritten(); + e.bytes = ((ByteArrayOutputStream)out).toByteArray(); + e.crc = crc.getValue(); + releaseDeflater(def); + update(e); + } + } + // Wrapper output stream class to write out a "stored" entry. // (1) this class does not close the underlying out stream when // being closed.