mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
143
src/java.base/share/classes/java/util/zip/Adler32.java
Normal file
143
src/java.base/share/classes/java/util/zip/Adler32.java
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
/**
|
||||
* A class that can be used to compute the Adler-32 checksum of a data
|
||||
* stream. An Adler-32 checksum is almost as reliable as a CRC-32 but
|
||||
* can be computed much faster.
|
||||
*
|
||||
* <p> Passing a {@code null} argument to a method in this class will cause
|
||||
* a {@link NullPointerException} to be thrown.</p>
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class Adler32 implements Checksum {
|
||||
|
||||
private int adler = 1;
|
||||
|
||||
/**
|
||||
* Creates a new Adler32 object.
|
||||
*/
|
||||
public Adler32() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the specified byte (the low eight
|
||||
* bits of the argument b).
|
||||
*/
|
||||
@Override
|
||||
public void update(int b) {
|
||||
adler = update(adler, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the specified array of bytes.
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* if {@code off} is negative, or {@code len} is negative, or
|
||||
* {@code off+len} is negative or greater than the length of
|
||||
* the array {@code b}.
|
||||
*/
|
||||
@Override
|
||||
public void update(byte[] b, int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
adler = updateBytes(adler, b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the bytes from the specified buffer.
|
||||
*
|
||||
* The checksum is updated with the remaining bytes in the buffer, starting
|
||||
* at the buffer's position. Upon return, the buffer's position will be
|
||||
* updated to its limit; its limit will not have been changed.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public void update(ByteBuffer buffer) {
|
||||
int pos = buffer.position();
|
||||
int limit = buffer.limit();
|
||||
assert (pos <= limit);
|
||||
int rem = limit - pos;
|
||||
if (rem <= 0)
|
||||
return;
|
||||
if (buffer instanceof DirectBuffer) {
|
||||
adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem);
|
||||
} else if (buffer.hasArray()) {
|
||||
adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem);
|
||||
} else {
|
||||
byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
|
||||
while (buffer.hasRemaining()) {
|
||||
int length = Math.min(buffer.remaining(), b.length);
|
||||
buffer.get(b, 0, length);
|
||||
update(b, 0, length);
|
||||
}
|
||||
}
|
||||
buffer.position(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the checksum to initial value.
|
||||
*/
|
||||
@Override
|
||||
public void reset() {
|
||||
adler = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the checksum value.
|
||||
*/
|
||||
@Override
|
||||
public long getValue() {
|
||||
return (long)adler & 0xffffffffL;
|
||||
}
|
||||
|
||||
private static native int update(int adler, int b);
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static native int updateBytes(int adler, byte[] b, int off,
|
||||
int len);
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static native int updateByteBuffer(int adler, long addr,
|
||||
int off, int len);
|
||||
|
||||
static {
|
||||
ZipUtils.loadLibrary();
|
||||
}
|
||||
}
|
179
src/java.base/share/classes/java/util/zip/CRC32.java
Normal file
179
src/java.base/share/classes/java/util/zip/CRC32.java
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
/**
|
||||
* A class that can be used to compute the CRC-32 of a data stream.
|
||||
*
|
||||
* <p> Passing a {@code null} argument to a method in this class will cause
|
||||
* a {@link NullPointerException} to be thrown.</p>
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class CRC32 implements Checksum {
|
||||
private int crc;
|
||||
|
||||
/**
|
||||
* Creates a new CRC32 object.
|
||||
*/
|
||||
public CRC32() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the CRC-32 checksum with the specified byte (the low
|
||||
* eight bits of the argument b).
|
||||
*/
|
||||
@Override
|
||||
public void update(int b) {
|
||||
crc = update(crc, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32 checksum with the specified array of bytes.
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* if {@code off} is negative, or {@code len} is negative, or
|
||||
* {@code off+len} is negative or greater than the length of
|
||||
* the array {@code b}.
|
||||
*/
|
||||
@Override
|
||||
public void update(byte[] b, int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
crc = updateBytes(crc, b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32 checksum with the bytes from the specified buffer.
|
||||
*
|
||||
* The checksum is updated with the remaining bytes in the buffer, starting
|
||||
* at the buffer's position. Upon return, the buffer's position will be
|
||||
* updated to its limit; its limit will not have been changed.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public void update(ByteBuffer buffer) {
|
||||
int pos = buffer.position();
|
||||
int limit = buffer.limit();
|
||||
assert (pos <= limit);
|
||||
int rem = limit - pos;
|
||||
if (rem <= 0)
|
||||
return;
|
||||
if (buffer instanceof DirectBuffer) {
|
||||
crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem);
|
||||
} else if (buffer.hasArray()) {
|
||||
crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), rem);
|
||||
} else {
|
||||
byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
|
||||
while (buffer.hasRemaining()) {
|
||||
int length = Math.min(buffer.remaining(), b.length);
|
||||
buffer.get(b, 0, length);
|
||||
update(b, 0, length);
|
||||
}
|
||||
}
|
||||
buffer.position(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets CRC-32 to initial value.
|
||||
*/
|
||||
@Override
|
||||
public void reset() {
|
||||
crc = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns CRC-32 value.
|
||||
*/
|
||||
@Override
|
||||
public long getValue() {
|
||||
return (long)crc & 0xffffffffL;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static native int update(int crc, int b);
|
||||
|
||||
private static int updateBytes(int crc, byte[] b, int off, int len) {
|
||||
updateBytesCheck(b, off, len);
|
||||
return updateBytes0(crc, b, off, len);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static native int updateBytes0(int crc, byte[] b, int off, int len);
|
||||
|
||||
private static void updateBytesCheck(byte[] b, int off, int len) {
|
||||
if (len <= 0) {
|
||||
return; // not an error because updateBytesImpl won't execute if len <= 0
|
||||
}
|
||||
|
||||
Objects.requireNonNull(b);
|
||||
|
||||
if (off < 0 || off >= b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(off);
|
||||
}
|
||||
|
||||
int endIndex = off + len - 1;
|
||||
if (endIndex < 0 || endIndex >= b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int updateByteBuffer(int alder, long addr,
|
||||
int off, int len) {
|
||||
updateByteBufferCheck(addr);
|
||||
return updateByteBuffer0(alder, addr, off, len);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static native int updateByteBuffer0(int alder, long addr,
|
||||
int off, int len);
|
||||
|
||||
private static void updateByteBufferCheck(long addr) {
|
||||
// Performs only a null check because bounds checks
|
||||
// are not easy to do on raw addresses.
|
||||
if (addr == 0L) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
ZipUtils.loadLibrary();
|
||||
}
|
||||
}
|
343
src/java.base/share/classes/java/util/zip/CRC32C.java
Normal file
343
src/java.base/share/classes/java/util/zip/CRC32C.java
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util.zip;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
|
||||
/**
|
||||
* A class that can be used to compute the CRC-32C of a data stream.
|
||||
*
|
||||
* <p>
|
||||
* CRC-32C is defined in <a href="http://www.ietf.org/rfc/rfc3720.txt">RFC
|
||||
* 3720</a>: Internet Small Computer Systems Interface (iSCSI).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Passing a {@code null} argument to a method in this class will cause a
|
||||
* {@link NullPointerException} to be thrown.
|
||||
* </p>
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public final class CRC32C implements Checksum {
|
||||
|
||||
/*
|
||||
* This CRC-32C implementation uses the 'slicing-by-8' algorithm described
|
||||
* in the paper "A Systematic Approach to Building High Performance
|
||||
* Software-Based CRC Generators" by Michael E. Kounavis and Frank L. Berry,
|
||||
* Intel Research and Development
|
||||
*/
|
||||
|
||||
/**
|
||||
* CRC-32C Polynomial
|
||||
*/
|
||||
private static final int CRC32C_POLY = 0x1EDC6F41;
|
||||
private static final int REVERSED_CRC32C_POLY = Integer.reverse(CRC32C_POLY);
|
||||
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
// Lookup tables
|
||||
// Lookup table for single byte calculations
|
||||
private static final int[] byteTable;
|
||||
// Lookup tables for bulk operations in 'slicing-by-8' algorithm
|
||||
private static final int[][] byteTables = new int[8][256];
|
||||
private static final int[] byteTable0 = byteTables[0];
|
||||
private static final int[] byteTable1 = byteTables[1];
|
||||
private static final int[] byteTable2 = byteTables[2];
|
||||
private static final int[] byteTable3 = byteTables[3];
|
||||
private static final int[] byteTable4 = byteTables[4];
|
||||
private static final int[] byteTable5 = byteTables[5];
|
||||
private static final int[] byteTable6 = byteTables[6];
|
||||
private static final int[] byteTable7 = byteTables[7];
|
||||
|
||||
static {
|
||||
// Generate lookup tables
|
||||
// High-order polynomial term stored in LSB of r.
|
||||
for (int index = 0; index < byteTables[0].length; index++) {
|
||||
int r = index;
|
||||
for (int i = 0; i < Byte.SIZE; i++) {
|
||||
if ((r & 1) != 0) {
|
||||
r = (r >>> 1) ^ REVERSED_CRC32C_POLY;
|
||||
} else {
|
||||
r >>>= 1;
|
||||
}
|
||||
}
|
||||
byteTables[0][index] = r;
|
||||
}
|
||||
|
||||
for (int index = 0; index < byteTables[0].length; index++) {
|
||||
int r = byteTables[0][index];
|
||||
|
||||
for (int k = 1; k < byteTables.length; k++) {
|
||||
r = byteTables[0][r & 0xFF] ^ (r >>> 8);
|
||||
byteTables[k][index] = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
||||
byteTable = byteTables[0];
|
||||
} else { // ByteOrder.BIG_ENDIAN
|
||||
byteTable = new int[byteTable0.length];
|
||||
System.arraycopy(byteTable0, 0, byteTable, 0, byteTable0.length);
|
||||
for (int[] table : byteTables) {
|
||||
for (int index = 0; index < table.length; index++) {
|
||||
table[index] = Integer.reverseBytes(table[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculated CRC-32C value
|
||||
*/
|
||||
private int crc = 0xFFFFFFFF;
|
||||
|
||||
/**
|
||||
* Creates a new CRC32C object.
|
||||
*/
|
||||
public CRC32C() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32C checksum with the specified byte (the low eight bits
|
||||
* of the argument b).
|
||||
*/
|
||||
@Override
|
||||
public void update(int b) {
|
||||
crc = (crc >>> 8) ^ byteTable[(crc ^ (b & 0xFF)) & 0xFF];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32C checksum with the specified array of bytes.
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* if {@code off} is negative, or {@code len} is negative, or
|
||||
* {@code off+len} is negative or greater than the length of
|
||||
* the array {@code b}.
|
||||
*/
|
||||
@Override
|
||||
public void update(byte[] b, int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
crc = updateBytes(crc, b, off, (off + len));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32C checksum with the bytes from the specified buffer.
|
||||
*
|
||||
* The checksum is updated with the remaining bytes in the buffer, starting
|
||||
* at the buffer's position. Upon return, the buffer's position will be
|
||||
* updated to its limit; its limit will not have been changed.
|
||||
*/
|
||||
@Override
|
||||
public void update(ByteBuffer buffer) {
|
||||
int pos = buffer.position();
|
||||
int limit = buffer.limit();
|
||||
assert (pos <= limit);
|
||||
int rem = limit - pos;
|
||||
if (rem <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer instanceof DirectBuffer) {
|
||||
crc = updateDirectByteBuffer(crc, ((DirectBuffer) buffer).address(),
|
||||
pos, limit);
|
||||
} else if (buffer.hasArray()) {
|
||||
crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(),
|
||||
limit + buffer.arrayOffset());
|
||||
} else {
|
||||
byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
|
||||
while (buffer.hasRemaining()) {
|
||||
int length = Math.min(buffer.remaining(), b.length);
|
||||
buffer.get(b, 0, length);
|
||||
update(b, 0, length);
|
||||
}
|
||||
}
|
||||
buffer.position(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets CRC-32C to initial value.
|
||||
*/
|
||||
@Override
|
||||
public void reset() {
|
||||
crc = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns CRC-32C value.
|
||||
*/
|
||||
@Override
|
||||
public long getValue() {
|
||||
return (~crc) & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32C checksum with the specified array of bytes.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static int updateBytes(int crc, byte[] b, int off, int end) {
|
||||
|
||||
// Do only byte reads for arrays so short they can't be aligned
|
||||
// or if bytes are stored with a larger witdh than one byte.,%
|
||||
if (end - off >= 8 && Unsafe.ARRAY_BYTE_INDEX_SCALE == 1) {
|
||||
|
||||
// align on 8 bytes
|
||||
int alignLength
|
||||
= (8 - ((Unsafe.ARRAY_BYTE_BASE_OFFSET + off) & 0x7)) & 0x7;
|
||||
for (int alignEnd = off + alignLength; off < alignEnd; off++) {
|
||||
crc = (crc >>> 8) ^ byteTable[(crc ^ b[off]) & 0xFF];
|
||||
}
|
||||
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
crc = Integer.reverseBytes(crc);
|
||||
}
|
||||
|
||||
// slicing-by-8
|
||||
for (; off < (end - Long.BYTES); off += Long.BYTES) {
|
||||
int firstHalf;
|
||||
int secondHalf;
|
||||
if (Unsafe.ADDRESS_SIZE == 4) {
|
||||
// On 32 bit platforms read two ints instead of a single 64bit long
|
||||
firstHalf = UNSAFE.getInt(b, (long)Unsafe.ARRAY_BYTE_BASE_OFFSET + off);
|
||||
secondHalf = UNSAFE.getInt(b, (long)Unsafe.ARRAY_BYTE_BASE_OFFSET + off
|
||||
+ Integer.BYTES);
|
||||
} else {
|
||||
long value = UNSAFE.getLong(b, (long)Unsafe.ARRAY_BYTE_BASE_OFFSET + off);
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
||||
firstHalf = (int) value;
|
||||
secondHalf = (int) (value >>> 32);
|
||||
} else { // ByteOrder.BIG_ENDIAN
|
||||
firstHalf = (int) (value >>> 32);
|
||||
secondHalf = (int) value;
|
||||
}
|
||||
}
|
||||
crc ^= firstHalf;
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
||||
crc = byteTable7[crc & 0xFF]
|
||||
^ byteTable6[(crc >>> 8) & 0xFF]
|
||||
^ byteTable5[(crc >>> 16) & 0xFF]
|
||||
^ byteTable4[crc >>> 24]
|
||||
^ byteTable3[secondHalf & 0xFF]
|
||||
^ byteTable2[(secondHalf >>> 8) & 0xFF]
|
||||
^ byteTable1[(secondHalf >>> 16) & 0xFF]
|
||||
^ byteTable0[secondHalf >>> 24];
|
||||
} else { // ByteOrder.BIG_ENDIAN
|
||||
crc = byteTable0[secondHalf & 0xFF]
|
||||
^ byteTable1[(secondHalf >>> 8) & 0xFF]
|
||||
^ byteTable2[(secondHalf >>> 16) & 0xFF]
|
||||
^ byteTable3[secondHalf >>> 24]
|
||||
^ byteTable4[crc & 0xFF]
|
||||
^ byteTable5[(crc >>> 8) & 0xFF]
|
||||
^ byteTable6[(crc >>> 16) & 0xFF]
|
||||
^ byteTable7[crc >>> 24];
|
||||
}
|
||||
}
|
||||
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
crc = Integer.reverseBytes(crc);
|
||||
}
|
||||
}
|
||||
|
||||
// Tail
|
||||
for (; off < end; off++) {
|
||||
crc = (crc >>> 8) ^ byteTable[(crc ^ b[off]) & 0xFF];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the CRC-32C checksum reading from the specified address.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static int updateDirectByteBuffer(int crc, long address,
|
||||
int off, int end) {
|
||||
|
||||
// Do only byte reads for arrays so short they can't be aligned
|
||||
if (end - off >= 8) {
|
||||
|
||||
// align on 8 bytes
|
||||
int alignLength = (8 - (int) ((address + off) & 0x7)) & 0x7;
|
||||
for (int alignEnd = off + alignLength; off < alignEnd; off++) {
|
||||
crc = (crc >>> 8)
|
||||
^ byteTable[(crc ^ UNSAFE.getByte(address + off)) & 0xFF];
|
||||
}
|
||||
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
crc = Integer.reverseBytes(crc);
|
||||
}
|
||||
|
||||
// slicing-by-8
|
||||
for (; off <= (end - Long.BYTES); off += Long.BYTES) {
|
||||
// Always reading two ints as reading a long followed by
|
||||
// shifting and casting was slower.
|
||||
int firstHalf = UNSAFE.getInt(address + off);
|
||||
int secondHalf = UNSAFE.getInt(address + off + Integer.BYTES);
|
||||
crc ^= firstHalf;
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
||||
crc = byteTable7[crc & 0xFF]
|
||||
^ byteTable6[(crc >>> 8) & 0xFF]
|
||||
^ byteTable5[(crc >>> 16) & 0xFF]
|
||||
^ byteTable4[crc >>> 24]
|
||||
^ byteTable3[secondHalf & 0xFF]
|
||||
^ byteTable2[(secondHalf >>> 8) & 0xFF]
|
||||
^ byteTable1[(secondHalf >>> 16) & 0xFF]
|
||||
^ byteTable0[secondHalf >>> 24];
|
||||
} else { // ByteOrder.BIG_ENDIAN
|
||||
crc = byteTable0[secondHalf & 0xFF]
|
||||
^ byteTable1[(secondHalf >>> 8) & 0xFF]
|
||||
^ byteTable2[(secondHalf >>> 16) & 0xFF]
|
||||
^ byteTable3[secondHalf >>> 24]
|
||||
^ byteTable4[crc & 0xFF]
|
||||
^ byteTable5[(crc >>> 8) & 0xFF]
|
||||
^ byteTable6[(crc >>> 16) & 0xFF]
|
||||
^ byteTable7[crc >>> 24];
|
||||
}
|
||||
}
|
||||
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
crc = Integer.reverseBytes(crc);
|
||||
}
|
||||
}
|
||||
|
||||
// Tail
|
||||
for (; off < end; off++) {
|
||||
crc = (crc >>> 8)
|
||||
^ byteTable[(crc ^ UNSAFE.getByte(address + off)) & 0xFF];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An input stream that also maintains a checksum of the data being read.
|
||||
* The checksum can then be used to verify the integrity of the input data.
|
||||
*
|
||||
* @see Checksum
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class CheckedInputStream extends FilterInputStream {
|
||||
private Checksum cksum;
|
||||
|
||||
/**
|
||||
* Creates an input stream using the specified Checksum.
|
||||
* @param in the input stream
|
||||
* @param cksum the Checksum
|
||||
*/
|
||||
public CheckedInputStream(InputStream in, Checksum cksum) {
|
||||
super(in);
|
||||
this.cksum = cksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte. Will block if no input is available.
|
||||
* @return the byte read, or -1 if the end of the stream is reached.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
int b = in.read();
|
||||
if (b != -1) {
|
||||
cksum.update(b);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads into an array of bytes. If <code>len</code> is not zero, the method
|
||||
* blocks until some input is available; otherwise, no
|
||||
* bytes are read and <code>0</code> is returned.
|
||||
* @param buf the buffer into which the data is read
|
||||
* @param off the start offset in the destination array <code>b</code>
|
||||
* @param len the maximum number of bytes read
|
||||
* @return the actual number of bytes read, or -1 if the end
|
||||
* of the stream is reached.
|
||||
* @exception NullPointerException If <code>buf</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
|
||||
* <code>len</code> is negative, or <code>len</code> is greater than
|
||||
* <code>buf.length - off</code>
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public int read(byte[] buf, int off, int len) throws IOException {
|
||||
len = in.read(buf, off, len);
|
||||
if (len != -1) {
|
||||
cksum.update(buf, off, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips specified number of bytes of input.
|
||||
* @param n the number of bytes to skip
|
||||
* @return the actual number of bytes skipped
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
byte[] buf = new byte[512];
|
||||
long total = 0;
|
||||
while (total < n) {
|
||||
long len = n - total;
|
||||
len = read(buf, 0, len < buf.length ? (int)len : buf.length);
|
||||
if (len == -1) {
|
||||
return total;
|
||||
}
|
||||
total += len;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Checksum for this input stream.
|
||||
* @return the Checksum value
|
||||
*/
|
||||
public Checksum getChecksum() {
|
||||
return cksum;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An output stream that also maintains a checksum of the data being
|
||||
* written. The checksum can then be used to verify the integrity of
|
||||
* the output data.
|
||||
*
|
||||
* @see Checksum
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class CheckedOutputStream extends FilterOutputStream {
|
||||
private Checksum cksum;
|
||||
|
||||
/**
|
||||
* Creates an output stream with the specified Checksum.
|
||||
* @param out the output stream
|
||||
* @param cksum the checksum
|
||||
*/
|
||||
public CheckedOutputStream(OutputStream out, Checksum cksum) {
|
||||
super(out);
|
||||
this.cksum = cksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte. Will block until the byte is actually written.
|
||||
* @param b the byte to be written
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
out.write(b);
|
||||
cksum.update(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes. Will block until the bytes are
|
||||
* actually written.
|
||||
* @param b the data to be written
|
||||
* @param off the start offset of the data
|
||||
* @param len the number of bytes to be written
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
out.write(b, off, len);
|
||||
cksum.update(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Checksum for this output stream.
|
||||
* @return the Checksum
|
||||
*/
|
||||
public Checksum getChecksum() {
|
||||
return cksum;
|
||||
}
|
||||
}
|
137
src/java.base/share/classes/java/util/zip/Checksum.java
Normal file
137
src/java.base/share/classes/java/util/zip/Checksum.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util.zip;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* An interface representing a data checksum.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public interface Checksum {
|
||||
|
||||
/**
|
||||
* Updates the current checksum with the specified byte.
|
||||
*
|
||||
* @param b the byte to update the checksum with
|
||||
*/
|
||||
public void update(int b);
|
||||
|
||||
/**
|
||||
* Updates the current checksum with the specified array of bytes.
|
||||
*
|
||||
* @implSpec This default implementation is equal to calling
|
||||
* {@code update(b, 0, b.length)}.
|
||||
*
|
||||
* @param b the array of bytes to update the checksum with
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* if {@code b} is {@code null}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
default public void update(byte[] b) {
|
||||
update(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current checksum with the specified array of bytes.
|
||||
*
|
||||
* @param b the byte array to update the checksum with
|
||||
* @param off the start offset of the data
|
||||
* @param len the number of bytes to use for the update
|
||||
*/
|
||||
public void update(byte[] b, int off, int len);
|
||||
|
||||
/**
|
||||
* Updates the current checksum with the bytes from the specified buffer.
|
||||
*
|
||||
* The checksum is updated with the remaining bytes in the buffer, starting
|
||||
* at the buffer's position. Upon return, the buffer's position will be
|
||||
* updated to its limit; its limit will not have been changed.
|
||||
*
|
||||
* @apiNote For best performance with DirectByteBuffer and other ByteBuffer
|
||||
* implementations without a backing array implementers of this interface
|
||||
* should override this method.
|
||||
*
|
||||
* @implSpec The default implementation has the following behavior.<br>
|
||||
* For ByteBuffers backed by an accessible byte array.
|
||||
* <pre>{@code
|
||||
* update(buffer.array(),
|
||||
* buffer.position() + buffer.arrayOffset(),
|
||||
* buffer.remaining());
|
||||
* }</pre>
|
||||
* For ByteBuffers not backed by an accessible byte array.
|
||||
* <pre>{@code
|
||||
* byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
|
||||
* while (buffer.hasRemaining()) {
|
||||
* int length = Math.min(buffer.remaining(), b.length);
|
||||
* buffer.get(b, 0, length);
|
||||
* update(b, 0, length);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param buffer the ByteBuffer to update the checksum with
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* if {@code buffer} is {@code null}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
default public void update(ByteBuffer buffer) {
|
||||
int pos = buffer.position();
|
||||
int limit = buffer.limit();
|
||||
assert (pos <= limit);
|
||||
int rem = limit - pos;
|
||||
if (rem <= 0) {
|
||||
return;
|
||||
}
|
||||
if (buffer.hasArray()) {
|
||||
update(buffer.array(), pos + buffer.arrayOffset(), rem);
|
||||
} else {
|
||||
byte[] b = new byte[Math.min(buffer.remaining(), 4096)];
|
||||
while (buffer.hasRemaining()) {
|
||||
int length = Math.min(buffer.remaining(), b.length);
|
||||
buffer.get(b, 0, length);
|
||||
update(b, 0, length);
|
||||
}
|
||||
}
|
||||
buffer.position(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current checksum value.
|
||||
*
|
||||
* @return the current checksum value
|
||||
*/
|
||||
public long getValue();
|
||||
|
||||
/**
|
||||
* Resets the checksum to its initial value.
|
||||
*/
|
||||
public void reset();
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/**
|
||||
* Signals that a data format error has occurred.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class DataFormatException extends Exception {
|
||||
private static final long serialVersionUID = 2219632870893641452L;
|
||||
|
||||
/**
|
||||
* Constructs a DataFormatException with no detail message.
|
||||
*/
|
||||
public DataFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a DataFormatException with the specified detail message.
|
||||
* A detail message is a String that describes this particular exception.
|
||||
* @param s the String containing a detail message
|
||||
*/
|
||||
public DataFormatException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
584
src/java.base/share/classes/java/util/zip/Deflater.java
Normal file
584
src/java.base/share/classes/java/util/zip/Deflater.java
Normal file
|
@ -0,0 +1,584 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/**
|
||||
* This class provides support for general purpose compression using the
|
||||
* popular ZLIB compression library. The ZLIB compression library was
|
||||
* initially developed as part of the PNG graphics standard and is not
|
||||
* protected by patents. It is fully described in the specifications at
|
||||
* the <a href="package-summary.html#package.description">java.util.zip
|
||||
* package description</a>.
|
||||
*
|
||||
* <p>The following code fragment demonstrates a trivial compression
|
||||
* and decompression of a string using {@code Deflater} and
|
||||
* {@code Inflater}.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* try {
|
||||
* // Encode a String into bytes
|
||||
* String inputString = "blahblahblah";
|
||||
* byte[] input = inputString.getBytes("UTF-8");
|
||||
*
|
||||
* // Compress the bytes
|
||||
* byte[] output = new byte[100];
|
||||
* Deflater compresser = new Deflater();
|
||||
* compresser.setInput(input);
|
||||
* compresser.finish();
|
||||
* int compressedDataLength = compresser.deflate(output);
|
||||
* compresser.end();
|
||||
*
|
||||
* // Decompress the bytes
|
||||
* Inflater decompresser = new Inflater();
|
||||
* decompresser.setInput(output, 0, compressedDataLength);
|
||||
* byte[] result = new byte[100];
|
||||
* int resultLength = decompresser.inflate(result);
|
||||
* decompresser.end();
|
||||
*
|
||||
* // Decode the bytes into a String
|
||||
* String outputString = new String(result, 0, resultLength, "UTF-8");
|
||||
* } catch(java.io.UnsupportedEncodingException ex) {
|
||||
* // handle
|
||||
* } catch (java.util.zip.DataFormatException ex) {
|
||||
* // handle
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @see Inflater
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class Deflater {
|
||||
|
||||
private final ZStreamRef zsRef;
|
||||
private byte[] buf = new byte[0];
|
||||
private int off, len;
|
||||
private int level, strategy;
|
||||
private boolean setParams;
|
||||
private boolean finish, finished;
|
||||
private long bytesRead;
|
||||
private long bytesWritten;
|
||||
|
||||
/**
|
||||
* Compression method for the deflate algorithm (the only one currently
|
||||
* supported).
|
||||
*/
|
||||
public static final int DEFLATED = 8;
|
||||
|
||||
/**
|
||||
* Compression level for no compression.
|
||||
*/
|
||||
public static final int NO_COMPRESSION = 0;
|
||||
|
||||
/**
|
||||
* Compression level for fastest compression.
|
||||
*/
|
||||
public static final int BEST_SPEED = 1;
|
||||
|
||||
/**
|
||||
* Compression level for best compression.
|
||||
*/
|
||||
public static final int BEST_COMPRESSION = 9;
|
||||
|
||||
/**
|
||||
* Default compression level.
|
||||
*/
|
||||
public static final int DEFAULT_COMPRESSION = -1;
|
||||
|
||||
/**
|
||||
* Compression strategy best used for data consisting mostly of small
|
||||
* values with a somewhat random distribution. Forces more Huffman coding
|
||||
* and less string matching.
|
||||
*/
|
||||
public static final int FILTERED = 1;
|
||||
|
||||
/**
|
||||
* Compression strategy for Huffman coding only.
|
||||
*/
|
||||
public static final int HUFFMAN_ONLY = 2;
|
||||
|
||||
/**
|
||||
* Default compression strategy.
|
||||
*/
|
||||
public static final int DEFAULT_STRATEGY = 0;
|
||||
|
||||
/**
|
||||
* Compression flush mode used to achieve best compression result.
|
||||
*
|
||||
* @see Deflater#deflate(byte[], int, int, int)
|
||||
* @since 1.7
|
||||
*/
|
||||
public static final int NO_FLUSH = 0;
|
||||
|
||||
/**
|
||||
* Compression flush mode used to flush out all pending output; may
|
||||
* degrade compression for some compression algorithms.
|
||||
*
|
||||
* @see Deflater#deflate(byte[], int, int, int)
|
||||
* @since 1.7
|
||||
*/
|
||||
public static final int SYNC_FLUSH = 2;
|
||||
|
||||
/**
|
||||
* Compression flush mode used to flush out all pending output and
|
||||
* reset the deflater. Using this mode too often can seriously degrade
|
||||
* compression.
|
||||
*
|
||||
* @see Deflater#deflate(byte[], int, int, int)
|
||||
* @since 1.7
|
||||
*/
|
||||
public static final int FULL_FLUSH = 3;
|
||||
|
||||
static {
|
||||
ZipUtils.loadLibrary();
|
||||
initIDs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new compressor using the specified compression level.
|
||||
* If 'nowrap' is true then the ZLIB header and checksum fields will
|
||||
* not be used in order to support the compression format used in
|
||||
* both GZIP and PKZIP.
|
||||
* @param level the compression level (0-9)
|
||||
* @param nowrap if true then use GZIP compatible compression
|
||||
*/
|
||||
public Deflater(int level, boolean nowrap) {
|
||||
this.level = level;
|
||||
this.strategy = DEFAULT_STRATEGY;
|
||||
this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new compressor using the specified compression level.
|
||||
* Compressed data will be generated in ZLIB format.
|
||||
* @param level the compression level (0-9)
|
||||
*/
|
||||
public Deflater(int level) {
|
||||
this(level, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new compressor with the default compression level.
|
||||
* Compressed data will be generated in ZLIB format.
|
||||
*/
|
||||
public Deflater() {
|
||||
this(DEFAULT_COMPRESSION, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input data for compression. This should be called whenever
|
||||
* needsInput() returns true indicating that more input data is required.
|
||||
* @param b the input data bytes
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @see Deflater#needsInput
|
||||
*/
|
||||
public void setInput(byte[] b, int off, int len) {
|
||||
if (b== null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
this.buf = b;
|
||||
this.off = off;
|
||||
this.len = len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input data for compression. This should be called whenever
|
||||
* needsInput() returns true indicating that more input data is required.
|
||||
* @param b the input data bytes
|
||||
* @see Deflater#needsInput
|
||||
*/
|
||||
public void setInput(byte[] b) {
|
||||
setInput(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets preset dictionary for compression. A preset dictionary is used
|
||||
* when the history buffer can be predetermined. When the data is later
|
||||
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
||||
* in order to get the Adler-32 value of the dictionary required for
|
||||
* decompression.
|
||||
* @param b the dictionary data bytes
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @see Inflater#inflate
|
||||
* @see Inflater#getAdler
|
||||
*/
|
||||
public void setDictionary(byte[] b, int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
setDictionary(zsRef.address(), b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets preset dictionary for compression. A preset dictionary is used
|
||||
* when the history buffer can be predetermined. When the data is later
|
||||
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
||||
* in order to get the Adler-32 value of the dictionary required for
|
||||
* decompression.
|
||||
* @param b the dictionary data bytes
|
||||
* @see Inflater#inflate
|
||||
* @see Inflater#getAdler
|
||||
*/
|
||||
public void setDictionary(byte[] b) {
|
||||
setDictionary(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the compression strategy to the specified value.
|
||||
*
|
||||
* <p> If the compression strategy is changed, the next invocation
|
||||
* of {@code deflate} will compress the input available so far with
|
||||
* the old strategy (and may be flushed); the new strategy will take
|
||||
* effect only after that invocation.
|
||||
*
|
||||
* @param strategy the new compression strategy
|
||||
* @exception IllegalArgumentException if the compression strategy is
|
||||
* invalid
|
||||
*/
|
||||
public void setStrategy(int strategy) {
|
||||
switch (strategy) {
|
||||
case DEFAULT_STRATEGY:
|
||||
case FILTERED:
|
||||
case HUFFMAN_ONLY:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
if (this.strategy != strategy) {
|
||||
this.strategy = strategy;
|
||||
setParams = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the compression level to the specified value.
|
||||
*
|
||||
* <p> If the compression level is changed, the next invocation
|
||||
* of {@code deflate} will compress the input available so far
|
||||
* with the old level (and may be flushed); the new level will
|
||||
* take effect only after that invocation.
|
||||
*
|
||||
* @param level the new compression level (0-9)
|
||||
* @exception IllegalArgumentException if the compression level is invalid
|
||||
*/
|
||||
public void setLevel(int level) {
|
||||
if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) {
|
||||
throw new IllegalArgumentException("invalid compression level");
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
if (this.level != level) {
|
||||
this.level = level;
|
||||
setParams = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the input data buffer is empty and setInput()
|
||||
* should be called in order to provide more input.
|
||||
* @return true if the input data buffer is empty and setInput()
|
||||
* should be called in order to provide more input
|
||||
*/
|
||||
public boolean needsInput() {
|
||||
synchronized (zsRef) {
|
||||
return len <= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When called, indicates that compression should end with the current
|
||||
* contents of the input buffer.
|
||||
*/
|
||||
public void finish() {
|
||||
synchronized (zsRef) {
|
||||
finish = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the end of the compressed data output stream has
|
||||
* been reached.
|
||||
* @return true if the end of the compressed data output stream has
|
||||
* been reached
|
||||
*/
|
||||
public boolean finished() {
|
||||
synchronized (zsRef) {
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the input data and fills specified buffer with compressed
|
||||
* data. Returns actual number of bytes of compressed data. A return value
|
||||
* of 0 indicates that {@link #needsInput() needsInput} should be called
|
||||
* in order to determine if more input data is required.
|
||||
*
|
||||
* <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
|
||||
* An invocation of this method of the form {@code deflater.deflate(b, off, len)}
|
||||
* yields the same result as the invocation of
|
||||
* {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
|
||||
*
|
||||
* @param b the buffer for the compressed data
|
||||
* @param off the start offset of the data
|
||||
* @param len the maximum number of bytes of compressed data
|
||||
* @return the actual number of bytes of compressed data written to the
|
||||
* output buffer
|
||||
*/
|
||||
public int deflate(byte[] b, int off, int len) {
|
||||
return deflate(b, off, len, NO_FLUSH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the input data and fills specified buffer with compressed
|
||||
* data. Returns actual number of bytes of compressed data. A return value
|
||||
* of 0 indicates that {@link #needsInput() needsInput} should be called
|
||||
* in order to determine if more input data is required.
|
||||
*
|
||||
* <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
|
||||
* An invocation of this method of the form {@code deflater.deflate(b)}
|
||||
* yields the same result as the invocation of
|
||||
* {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
|
||||
*
|
||||
* @param b the buffer for the compressed data
|
||||
* @return the actual number of bytes of compressed data written to the
|
||||
* output buffer
|
||||
*/
|
||||
public int deflate(byte[] b) {
|
||||
return deflate(b, 0, b.length, NO_FLUSH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses the input data and fills the specified buffer with compressed
|
||||
* data. Returns actual number of bytes of data compressed.
|
||||
*
|
||||
* <p>Compression flush mode is one of the following three modes:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
|
||||
* to accumulate, before producing output, in order to achieve the best
|
||||
* compression (should be used in normal use scenario). A return value
|
||||
* of 0 in this flush mode indicates that {@link #needsInput()} should
|
||||
* be called in order to determine if more input data is required.
|
||||
*
|
||||
* <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
|
||||
* to the specified output buffer, so that an inflater that works on
|
||||
* compressed data can get all input data available so far (In particular
|
||||
* the {@link #needsInput()} returns {@code true} after this invocation
|
||||
* if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
|
||||
* may degrade compression for some compression algorithms and so it
|
||||
* should be used only when necessary.
|
||||
*
|
||||
* <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
|
||||
* {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
|
||||
* that works on the compressed output data can restart from this point
|
||||
* if previous compressed data has been damaged or if random access is
|
||||
* desired. Using {@link #FULL_FLUSH} too often can seriously degrade
|
||||
* compression.
|
||||
* </ul>
|
||||
*
|
||||
* <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
|
||||
* the return value is {@code len}, the space available in output
|
||||
* buffer {@code b}, this method should be invoked again with the same
|
||||
* {@code flush} parameter and more output space. Make sure that
|
||||
* {@code len} is greater than 6 to avoid flush marker (5 bytes) being
|
||||
* repeatedly output to the output buffer every time this method is
|
||||
* invoked.
|
||||
*
|
||||
* @param b the buffer for the compressed data
|
||||
* @param off the start offset of the data
|
||||
* @param len the maximum number of bytes of compressed data
|
||||
* @param flush the compression flush mode
|
||||
* @return the actual number of bytes of compressed data written to
|
||||
* the output buffer
|
||||
*
|
||||
* @throws IllegalArgumentException if the flush mode is invalid
|
||||
* @since 1.7
|
||||
*/
|
||||
public int deflate(byte[] b, int off, int len, int flush) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
|
||||
flush == FULL_FLUSH) {
|
||||
int thisLen = this.len;
|
||||
int n = deflateBytes(zsRef.address(), b, off, len, flush);
|
||||
bytesWritten += n;
|
||||
bytesRead += (thisLen - this.len);
|
||||
return n;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ADLER-32 value of the uncompressed data.
|
||||
* @return the ADLER-32 value of the uncompressed data
|
||||
*/
|
||||
public int getAdler() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
return getAdler(zsRef.address());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of uncompressed bytes input so far.
|
||||
*
|
||||
* <p>Since the number of bytes may be greater than
|
||||
* Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
|
||||
* the preferred means of obtaining this information.</p>
|
||||
*
|
||||
* @return the total number of uncompressed bytes input so far
|
||||
*/
|
||||
public int getTotalIn() {
|
||||
return (int) getBytesRead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of uncompressed bytes input so far.
|
||||
*
|
||||
* @return the total (non-negative) number of uncompressed bytes input so far
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesRead() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of compressed bytes output so far.
|
||||
*
|
||||
* <p>Since the number of bytes may be greater than
|
||||
* Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
|
||||
* the preferred means of obtaining this information.</p>
|
||||
*
|
||||
* @return the total number of compressed bytes output so far
|
||||
*/
|
||||
public int getTotalOut() {
|
||||
return (int) getBytesWritten();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of compressed bytes output so far.
|
||||
*
|
||||
* @return the total (non-negative) number of compressed bytes output so far
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesWritten() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
return bytesWritten;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets deflater so that a new set of input data can be processed.
|
||||
* Keeps current compression level and strategy settings.
|
||||
*/
|
||||
public void reset() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
reset(zsRef.address());
|
||||
finish = false;
|
||||
finished = false;
|
||||
off = len = 0;
|
||||
bytesRead = bytesWritten = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the compressor and discards any unprocessed input.
|
||||
* This method should be called when the compressor is no longer
|
||||
* being used, but will also be called automatically by the
|
||||
* finalize() method. Once this method is called, the behavior
|
||||
* of the Deflater object is undefined.
|
||||
*/
|
||||
public void end() {
|
||||
synchronized (zsRef) {
|
||||
long addr = zsRef.address();
|
||||
zsRef.clear();
|
||||
if (addr != 0) {
|
||||
end(addr);
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the compressor when garbage is collected.
|
||||
*
|
||||
* @deprecated The {@code finalize} method has been deprecated.
|
||||
* Subclasses that override {@code finalize} in order to perform cleanup
|
||||
* should be modified to use alternative cleanup mechanisms and
|
||||
* to remove the overriding {@code finalize} method.
|
||||
* When overriding the {@code finalize} method, its implementation must explicitly
|
||||
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
|
||||
* See the specification for {@link Object#finalize()} for further
|
||||
* information about migration options.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
protected void finalize() {
|
||||
end();
|
||||
}
|
||||
|
||||
private void ensureOpen() {
|
||||
assert Thread.holdsLock(zsRef);
|
||||
if (zsRef.address() == 0)
|
||||
throw new NullPointerException("Deflater has been closed");
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
private static native long init(int level, int strategy, boolean nowrap);
|
||||
private static native void setDictionary(long addr, byte[] b, int off, int len);
|
||||
private native int deflateBytes(long addr, byte[] b, int off, int len,
|
||||
int flush);
|
||||
private static native int getAdler(long addr);
|
||||
private static native void reset(long addr);
|
||||
private static native void end(long addr);
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implements an input stream filter for compressing data in the "deflate"
|
||||
* compression format.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author David R Tribble (david@tribble.com)
|
||||
*
|
||||
* @see DeflaterOutputStream
|
||||
* @see InflaterOutputStream
|
||||
* @see InflaterInputStream
|
||||
*/
|
||||
|
||||
public class DeflaterInputStream extends FilterInputStream {
|
||||
/** Compressor for this stream. */
|
||||
protected final Deflater def;
|
||||
|
||||
/** Input buffer for reading compressed data. */
|
||||
protected final byte[] buf;
|
||||
|
||||
/** Temporary read buffer. */
|
||||
private byte[] rbuf = new byte[1];
|
||||
|
||||
/** Default compressor is used. */
|
||||
private boolean usesDefaultDeflater = false;
|
||||
|
||||
/** End of the underlying input stream has been reached. */
|
||||
private boolean reachEOF = false;
|
||||
|
||||
/**
|
||||
* Check to make sure that this stream has not been closed.
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (in == null) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream with a default compressor and buffer
|
||||
* size.
|
||||
*
|
||||
* @param in input stream to read the uncompressed data to
|
||||
* @throws NullPointerException if {@code in} is null
|
||||
*/
|
||||
public DeflaterInputStream(InputStream in) {
|
||||
this(in, new Deflater());
|
||||
usesDefaultDeflater = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream with the specified compressor and a
|
||||
* default buffer size.
|
||||
*
|
||||
* @param in input stream to read the uncompressed data to
|
||||
* @param defl compressor ("deflater") for this stream
|
||||
* @throws NullPointerException if {@code in} or {@code defl} is null
|
||||
*/
|
||||
public DeflaterInputStream(InputStream in, Deflater defl) {
|
||||
this(in, defl, 512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream with the specified compressor and buffer
|
||||
* size.
|
||||
*
|
||||
* @param in input stream to read the uncompressed data to
|
||||
* @param defl compressor ("deflater") for this stream
|
||||
* @param bufLen compression buffer size
|
||||
* @throws IllegalArgumentException if {@code bufLen <= 0}
|
||||
* @throws NullPointerException if {@code in} or {@code defl} is null
|
||||
*/
|
||||
public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) {
|
||||
super(in);
|
||||
|
||||
// Sanity checks
|
||||
if (in == null)
|
||||
throw new NullPointerException("Null input");
|
||||
if (defl == null)
|
||||
throw new NullPointerException("Null deflater");
|
||||
if (bufLen < 1)
|
||||
throw new IllegalArgumentException("Buffer size < 1");
|
||||
|
||||
// Initialize
|
||||
def = defl;
|
||||
buf = new byte[bufLen];
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and its underlying input stream, discarding
|
||||
* any pending uncompressed data.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (in != null) {
|
||||
try {
|
||||
// Clean up
|
||||
if (usesDefaultDeflater) {
|
||||
def.end();
|
||||
}
|
||||
|
||||
in.close();
|
||||
} finally {
|
||||
in = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single byte of compressed data from the input stream.
|
||||
* This method will block until some input can be read and compressed.
|
||||
*
|
||||
* @return a single byte of compressed data, or -1 if the end of the
|
||||
* uncompressed input stream is reached
|
||||
* @throws IOException if an I/O error occurs or if this stream is
|
||||
* already closed
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
// Read a single byte of compressed data
|
||||
int len = read(rbuf, 0, 1);
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
return (rbuf[0] & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads compressed data into a byte array.
|
||||
* This method will block until some input can be read and compressed.
|
||||
*
|
||||
* @param b buffer into which the data is read
|
||||
* @param off starting offset of the data within {@code b}
|
||||
* @param len maximum number of compressed bytes to read into {@code b}
|
||||
* @return the actual number of bytes read, or -1 if the end of the
|
||||
* uncompressed input stream is reached
|
||||
* @throws IndexOutOfBoundsException if {@code len > b.length - off}
|
||||
* @throws IOException if an I/O error occurs or if this input stream is
|
||||
* already closed
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
// Sanity checks
|
||||
ensureOpen();
|
||||
if (b == null) {
|
||||
throw new NullPointerException("Null buffer for read");
|
||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read and compress (deflate) input data bytes
|
||||
int cnt = 0;
|
||||
while (len > 0 && !def.finished()) {
|
||||
int n;
|
||||
|
||||
// Read data from the input stream
|
||||
if (def.needsInput()) {
|
||||
n = in.read(buf, 0, buf.length);
|
||||
if (n < 0) {
|
||||
// End of the input stream reached
|
||||
def.finish();
|
||||
} else if (n > 0) {
|
||||
def.setInput(buf, 0, n);
|
||||
}
|
||||
}
|
||||
|
||||
// Compress the input data, filling the read buffer
|
||||
n = def.deflate(b, off, len);
|
||||
cnt += n;
|
||||
off += n;
|
||||
len -= n;
|
||||
}
|
||||
if (cnt == 0 && def.finished()) {
|
||||
reachEOF = true;
|
||||
cnt = -1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over and discards data from the input stream.
|
||||
* This method may block until the specified number of bytes are read and
|
||||
* skipped. <em>Note:</em> While {@code n} is given as a {@code long},
|
||||
* the maximum number of bytes which can be skipped is
|
||||
* {@code Integer.MAX_VALUE}.
|
||||
*
|
||||
* @param n number of bytes to be skipped
|
||||
* @return the actual number of bytes skipped
|
||||
* @throws IOException if an I/O error occurs or if this stream is
|
||||
* already closed
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("negative skip length");
|
||||
}
|
||||
ensureOpen();
|
||||
|
||||
// Skip bytes by repeatedly decompressing small blocks
|
||||
if (rbuf.length < 512)
|
||||
rbuf = new byte[512];
|
||||
|
||||
int total = (int)Math.min(n, Integer.MAX_VALUE);
|
||||
long cnt = 0;
|
||||
while (total > 0) {
|
||||
// Read a small block of uncompressed bytes
|
||||
int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length));
|
||||
|
||||
if (len < 0) {
|
||||
break;
|
||||
}
|
||||
cnt += len;
|
||||
total -= len;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 after EOF has been reached, otherwise always return 1.
|
||||
* <p>
|
||||
* Programs should not count on this method to return the actual number
|
||||
* of bytes that could be read without blocking
|
||||
* @return zero after the end of the underlying input stream has been
|
||||
* reached, otherwise always returns 1
|
||||
* @throws IOException if an I/O error occurs or if this stream is
|
||||
* already closed
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
ensureOpen();
|
||||
if (reachEOF) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code false} because this input stream does not support
|
||||
* the {@link #mark mark()} and {@link #reset reset()} methods.
|
||||
*
|
||||
* @return false, always
|
||||
*/
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <i>This operation is not supported</i>.
|
||||
*
|
||||
* @param limit maximum bytes that can be read before invalidating the position marker
|
||||
*/
|
||||
public void mark(int limit) {
|
||||
// Operation not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* <i>This operation is not supported</i>.
|
||||
*
|
||||
* @throws IOException always thrown
|
||||
*/
|
||||
public void reset() throws IOException {
|
||||
throw new IOException("mark/reset not supported");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements an output stream filter for compressing data in
|
||||
* the "deflate" compression format. It is also used as the basis for other
|
||||
* types of compression filters, such as GZIPOutputStream.
|
||||
*
|
||||
* @see Deflater
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class DeflaterOutputStream extends FilterOutputStream {
|
||||
/**
|
||||
* Compressor for this stream.
|
||||
*/
|
||||
protected Deflater def;
|
||||
|
||||
/**
|
||||
* Output buffer for writing compressed data.
|
||||
*/
|
||||
protected byte[] buf;
|
||||
|
||||
/**
|
||||
* Indicates that the stream has been closed.
|
||||
*/
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
private final boolean syncFlush;
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified compressor,
|
||||
* buffer size and flush mode.
|
||||
|
||||
* @param out the output stream
|
||||
* @param def the compressor ("deflater")
|
||||
* @param size the output buffer size
|
||||
* @param syncFlush
|
||||
* if {@code true} the {@link #flush()} method of this
|
||||
* instance flushes the compressor with flush mode
|
||||
* {@link Deflater#SYNC_FLUSH} before flushing the output
|
||||
* stream, otherwise only flushes the output stream
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code size <= 0}
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public DeflaterOutputStream(OutputStream out,
|
||||
Deflater def,
|
||||
int size,
|
||||
boolean syncFlush) {
|
||||
super(out);
|
||||
if (out == null || def == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (size <= 0) {
|
||||
throw new IllegalArgumentException("buffer size <= 0");
|
||||
}
|
||||
this.def = def;
|
||||
this.buf = new byte[size];
|
||||
this.syncFlush = syncFlush;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified compressor and
|
||||
* buffer size.
|
||||
*
|
||||
* <p>The new output stream instance is created as if by invoking
|
||||
* the 4-argument constructor DeflaterOutputStream(out, def, size, false).
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param def the compressor ("deflater")
|
||||
* @param size the output buffer size
|
||||
* @exception IllegalArgumentException if {@code size <= 0}
|
||||
*/
|
||||
public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
|
||||
this(out, def, size, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified compressor, flush
|
||||
* mode and a default buffer size.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param def the compressor ("deflater")
|
||||
* @param syncFlush
|
||||
* if {@code true} the {@link #flush()} method of this
|
||||
* instance flushes the compressor with flush mode
|
||||
* {@link Deflater#SYNC_FLUSH} before flushing the output
|
||||
* stream, otherwise only flushes the output stream
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public DeflaterOutputStream(OutputStream out,
|
||||
Deflater def,
|
||||
boolean syncFlush) {
|
||||
this(out, def, 512, syncFlush);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified compressor and
|
||||
* a default buffer size.
|
||||
*
|
||||
* <p>The new output stream instance is created as if by invoking
|
||||
* the 3-argument constructor DeflaterOutputStream(out, def, false).
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param def the compressor ("deflater")
|
||||
*/
|
||||
public DeflaterOutputStream(OutputStream out, Deflater def) {
|
||||
this(out, def, 512, false);
|
||||
}
|
||||
|
||||
boolean usesDefaultDeflater = false;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new output stream with a default compressor, a default
|
||||
* buffer size and the specified flush mode.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param syncFlush
|
||||
* if {@code true} the {@link #flush()} method of this
|
||||
* instance flushes the compressor with flush mode
|
||||
* {@link Deflater#SYNC_FLUSH} before flushing the output
|
||||
* stream, otherwise only flushes the output stream
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public DeflaterOutputStream(OutputStream out, boolean syncFlush) {
|
||||
this(out, new Deflater(), 512, syncFlush);
|
||||
usesDefaultDeflater = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with a default compressor and buffer size.
|
||||
*
|
||||
* <p>The new output stream instance is created as if by invoking
|
||||
* the 2-argument constructor DeflaterOutputStream(out, false).
|
||||
*
|
||||
* @param out the output stream
|
||||
*/
|
||||
public DeflaterOutputStream(OutputStream out) {
|
||||
this(out, false);
|
||||
usesDefaultDeflater = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the compressed output stream. This method will
|
||||
* block until the byte can be written.
|
||||
* @param b the byte to be written
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
byte[] buf = new byte[1];
|
||||
buf[0] = (byte)(b & 0xff);
|
||||
write(buf, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes to the compressed output stream. This
|
||||
* method will block until all the bytes are written.
|
||||
* @param b the data to be written
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (def.finished()) {
|
||||
throw new IOException("write beyond end of stream");
|
||||
}
|
||||
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
if (!def.finished()) {
|
||||
def.setInput(b, off, len);
|
||||
while (!def.needsInput()) {
|
||||
deflate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes writing compressed data to the output stream without closing
|
||||
* the underlying stream. Use this method when applying multiple filters
|
||||
* in succession to the same output stream.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void finish() throws IOException {
|
||||
if (!def.finished()) {
|
||||
def.finish();
|
||||
while (!def.finished()) {
|
||||
deflate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes remaining compressed data to the output stream and closes the
|
||||
* underlying stream.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed) {
|
||||
finish();
|
||||
if (usesDefaultDeflater)
|
||||
def.end();
|
||||
out.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes next block of compressed data to the output stream.
|
||||
* @throws IOException if an I/O error has occurred
|
||||
*/
|
||||
protected void deflate() throws IOException {
|
||||
int len = def.deflate(buf, 0, buf.length);
|
||||
if (len > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the compressed output stream.
|
||||
*
|
||||
* If {@link #DeflaterOutputStream(OutputStream, Deflater, int, boolean)
|
||||
* syncFlush} is {@code true} when this compressed output stream is
|
||||
* constructed, this method first flushes the underlying {@code compressor}
|
||||
* with the flush mode {@link Deflater#SYNC_FLUSH} to force
|
||||
* all pending data to be flushed out to the output stream and then
|
||||
* flushes the output stream. Otherwise this method only flushes the
|
||||
* output stream without flushing the {@code compressor}.
|
||||
*
|
||||
* @throws IOException if an I/O error has occurred
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
if (syncFlush && !def.finished()) {
|
||||
int len = 0;
|
||||
while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0)
|
||||
{
|
||||
out.write(buf, 0, len);
|
||||
if (len < buf.length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
}
|
294
src/java.base/share/classes/java/util/zip/GZIPInputStream.java
Normal file
294
src/java.base/share/classes/java/util/zip/GZIPInputStream.java
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.SequenceInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
|
||||
/**
|
||||
* This class implements a stream filter for reading compressed data in
|
||||
* the GZIP file format.
|
||||
*
|
||||
* @see InflaterInputStream
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*
|
||||
*/
|
||||
public
|
||||
class GZIPInputStream extends InflaterInputStream {
|
||||
/**
|
||||
* CRC-32 for uncompressed data.
|
||||
*/
|
||||
protected CRC32 crc = new CRC32();
|
||||
|
||||
/**
|
||||
* Indicates end of input stream.
|
||||
*/
|
||||
protected boolean eos;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
/**
|
||||
* Check to make sure that this stream has not been closed
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream with the specified buffer size.
|
||||
* @param in the input stream
|
||||
* @param size the input buffer size
|
||||
*
|
||||
* @exception ZipException if a GZIP format error has occurred or the
|
||||
* compression method used is unsupported
|
||||
* @exception IOException if an I/O error has occurred
|
||||
* @exception IllegalArgumentException if {@code size <= 0}
|
||||
*/
|
||||
public GZIPInputStream(InputStream in, int size) throws IOException {
|
||||
super(in, new Inflater(true), size);
|
||||
usesDefaultInflater = true;
|
||||
readHeader(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream with a default buffer size.
|
||||
* @param in the input stream
|
||||
*
|
||||
* @exception ZipException if a GZIP format error has occurred or the
|
||||
* compression method used is unsupported
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public GZIPInputStream(InputStream in) throws IOException {
|
||||
this(in, 512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads uncompressed data into an array of bytes. If <code>len</code> is not
|
||||
* zero, the method will block until some input can be decompressed; otherwise,
|
||||
* no bytes are read and <code>0</code> is returned.
|
||||
* @param buf the buffer into which the data is read
|
||||
* @param off the start offset in the destination array <code>b</code>
|
||||
* @param len the maximum number of bytes read
|
||||
* @return the actual number of bytes read, or -1 if the end of the
|
||||
* compressed input stream is reached
|
||||
*
|
||||
* @exception NullPointerException If <code>buf</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
|
||||
* <code>len</code> is negative, or <code>len</code> is greater than
|
||||
* <code>buf.length - off</code>
|
||||
* @exception ZipException if the compressed input data is corrupt.
|
||||
* @exception IOException if an I/O error has occurred.
|
||||
*
|
||||
*/
|
||||
public int read(byte[] buf, int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
if (eos) {
|
||||
return -1;
|
||||
}
|
||||
int n = super.read(buf, off, len);
|
||||
if (n == -1) {
|
||||
if (readTrailer())
|
||||
eos = true;
|
||||
else
|
||||
return this.read(buf, off, len);
|
||||
} else {
|
||||
crc.update(buf, off, n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources associated
|
||||
* with the stream.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed) {
|
||||
super.close();
|
||||
eos = true;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GZIP header magic number.
|
||||
*/
|
||||
public static final int GZIP_MAGIC = 0x8b1f;
|
||||
|
||||
/*
|
||||
* File header flags.
|
||||
*/
|
||||
private static final int FTEXT = 1; // Extra text
|
||||
private static final int FHCRC = 2; // Header CRC
|
||||
private static final int FEXTRA = 4; // Extra field
|
||||
private static final int FNAME = 8; // File name
|
||||
private static final int FCOMMENT = 16; // File comment
|
||||
|
||||
/*
|
||||
* Reads GZIP member header and returns the total byte number
|
||||
* of this member header.
|
||||
*/
|
||||
private int readHeader(InputStream this_in) throws IOException {
|
||||
CheckedInputStream in = new CheckedInputStream(this_in, crc);
|
||||
crc.reset();
|
||||
// Check header magic
|
||||
if (readUShort(in) != GZIP_MAGIC) {
|
||||
throw new ZipException("Not in GZIP format");
|
||||
}
|
||||
// Check compression method
|
||||
if (readUByte(in) != 8) {
|
||||
throw new ZipException("Unsupported compression method");
|
||||
}
|
||||
// Read flags
|
||||
int flg = readUByte(in);
|
||||
// Skip MTIME, XFL, and OS fields
|
||||
skipBytes(in, 6);
|
||||
int n = 2 + 2 + 6;
|
||||
// Skip optional extra field
|
||||
if ((flg & FEXTRA) == FEXTRA) {
|
||||
int m = readUShort(in);
|
||||
skipBytes(in, m);
|
||||
n += m + 2;
|
||||
}
|
||||
// Skip optional file name
|
||||
if ((flg & FNAME) == FNAME) {
|
||||
do {
|
||||
n++;
|
||||
} while (readUByte(in) != 0);
|
||||
}
|
||||
// Skip optional file comment
|
||||
if ((flg & FCOMMENT) == FCOMMENT) {
|
||||
do {
|
||||
n++;
|
||||
} while (readUByte(in) != 0);
|
||||
}
|
||||
// Check optional header CRC
|
||||
if ((flg & FHCRC) == FHCRC) {
|
||||
int v = (int)crc.getValue() & 0xffff;
|
||||
if (readUShort(in) != v) {
|
||||
throw new ZipException("Corrupt GZIP header");
|
||||
}
|
||||
n += 2;
|
||||
}
|
||||
crc.reset();
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads GZIP member trailer and returns true if the eos
|
||||
* reached, false if there are more (concatenated gzip
|
||||
* data set)
|
||||
*/
|
||||
private boolean readTrailer() throws IOException {
|
||||
InputStream in = this.in;
|
||||
int n = inf.getRemaining();
|
||||
if (n > 0) {
|
||||
in = new SequenceInputStream(
|
||||
new ByteArrayInputStream(buf, len - n, n),
|
||||
new FilterInputStream(in) {
|
||||
public void close() throws IOException {}
|
||||
});
|
||||
}
|
||||
// Uses left-to-right evaluation order
|
||||
if ((readUInt(in) != crc.getValue()) ||
|
||||
// rfc1952; ISIZE is the input size modulo 2^32
|
||||
(readUInt(in) != (inf.getBytesWritten() & 0xffffffffL)))
|
||||
throw new ZipException("Corrupt GZIP trailer");
|
||||
|
||||
// If there are more bytes available in "in" or
|
||||
// the leftover in the "inf" is > 26 bytes:
|
||||
// this.trailer(8) + next.header.min(10) + next.trailer(8)
|
||||
// try concatenated case
|
||||
if (this.in.available() > 0 || n > 26) {
|
||||
int m = 8; // this.trailer
|
||||
try {
|
||||
m += readHeader(in); // next.header
|
||||
} catch (IOException ze) {
|
||||
return true; // ignore any malformed, do nothing
|
||||
}
|
||||
inf.reset();
|
||||
if (n > m)
|
||||
inf.setInput(buf, len - n + m, n - m);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads unsigned integer in Intel byte order.
|
||||
*/
|
||||
private long readUInt(InputStream in) throws IOException {
|
||||
long s = readUShort(in);
|
||||
return ((long)readUShort(in) << 16) | s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads unsigned short in Intel byte order.
|
||||
*/
|
||||
private int readUShort(InputStream in) throws IOException {
|
||||
int b = readUByte(in);
|
||||
return (readUByte(in) << 8) | b;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads unsigned byte.
|
||||
*/
|
||||
private int readUByte(InputStream in) throws IOException {
|
||||
int b = in.read();
|
||||
if (b == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
if (b < -1 || b > 255) {
|
||||
// Report on this.in, not argument in; see read{Header, Trailer}.
|
||||
throw new IOException(this.in.getClass().getName()
|
||||
+ ".read() returned value out of range -1..255: " + b);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private byte[] tmpbuf = new byte[128];
|
||||
|
||||
/*
|
||||
* Skips bytes of input data blocking until all bytes are skipped.
|
||||
* Does not assume that the input stream is capable of seeking.
|
||||
*/
|
||||
private void skipBytes(InputStream in, int n) throws IOException {
|
||||
while (n > 0) {
|
||||
int len = in.read(tmpbuf, 0, n < tmpbuf.length ? n : tmpbuf.length);
|
||||
if (len == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
n -= len;
|
||||
}
|
||||
}
|
||||
}
|
223
src/java.base/share/classes/java/util/zip/GZIPOutputStream.java
Normal file
223
src/java.base/share/classes/java/util/zip/GZIPOutputStream.java
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements a stream filter for writing compressed data in
|
||||
* the GZIP file format.
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*
|
||||
*/
|
||||
public
|
||||
class GZIPOutputStream extends DeflaterOutputStream {
|
||||
/**
|
||||
* CRC-32 of uncompressed data.
|
||||
*/
|
||||
protected CRC32 crc = new CRC32();
|
||||
|
||||
/*
|
||||
* GZIP header magic number.
|
||||
*/
|
||||
private static final int GZIP_MAGIC = 0x8b1f;
|
||||
|
||||
/*
|
||||
* Trailer size in bytes.
|
||||
*
|
||||
*/
|
||||
private static final int TRAILER_SIZE = 8;
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified buffer size.
|
||||
*
|
||||
* <p>The new output stream instance is created as if by invoking
|
||||
* the 3-argument constructor GZIPOutputStream(out, size, false).
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param size the output buffer size
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
* @exception IllegalArgumentException if {@code size <= 0}
|
||||
*/
|
||||
public GZIPOutputStream(OutputStream out, int size) throws IOException {
|
||||
this(out, size, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified buffer size and
|
||||
* flush mode.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param size the output buffer size
|
||||
* @param syncFlush
|
||||
* if {@code true} invocation of the inherited
|
||||
* {@link DeflaterOutputStream#flush() flush()} method of
|
||||
* this instance flushes the compressor with flush mode
|
||||
* {@link Deflater#SYNC_FLUSH} before flushing the output
|
||||
* stream, otherwise only flushes the output stream
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
* @exception IllegalArgumentException if {@code size <= 0}
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public GZIPOutputStream(OutputStream out, int size, boolean syncFlush)
|
||||
throws IOException
|
||||
{
|
||||
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true),
|
||||
size,
|
||||
syncFlush);
|
||||
usesDefaultDeflater = true;
|
||||
writeHeader();
|
||||
crc.reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new output stream with a default buffer size.
|
||||
*
|
||||
* <p>The new output stream instance is created as if by invoking
|
||||
* the 2-argument constructor GZIPOutputStream(out, false).
|
||||
*
|
||||
* @param out the output stream
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public GZIPOutputStream(OutputStream out) throws IOException {
|
||||
this(out, 512, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with a default buffer size and
|
||||
* the specified flush mode.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @param syncFlush
|
||||
* if {@code true} invocation of the inherited
|
||||
* {@link DeflaterOutputStream#flush() flush()} method of
|
||||
* this instance flushes the compressor with flush mode
|
||||
* {@link Deflater#SYNC_FLUSH} before flushing the output
|
||||
* stream, otherwise only flushes the output stream
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public GZIPOutputStream(OutputStream out, boolean syncFlush)
|
||||
throws IOException
|
||||
{
|
||||
this(out, 512, syncFlush);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes array of bytes to the compressed output stream. This method
|
||||
* will block until all the bytes are written.
|
||||
* @param buf the data to be written
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public synchronized void write(byte[] buf, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
super.write(buf, off, len);
|
||||
crc.update(buf, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes writing compressed data to the output stream without closing
|
||||
* the underlying stream. Use this method when applying multiple filters
|
||||
* in succession to the same output stream.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void finish() throws IOException {
|
||||
if (!def.finished()) {
|
||||
def.finish();
|
||||
while (!def.finished()) {
|
||||
int len = def.deflate(buf, 0, buf.length);
|
||||
if (def.finished() && len <= buf.length - TRAILER_SIZE) {
|
||||
// last deflater buffer. Fit trailer at the end
|
||||
writeTrailer(buf, len);
|
||||
len = len + TRAILER_SIZE;
|
||||
out.write(buf, 0, len);
|
||||
return;
|
||||
}
|
||||
if (len > 0)
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
// if we can't fit the trailer at the end of the last
|
||||
// deflater buffer, we write it separately
|
||||
byte[] trailer = new byte[TRAILER_SIZE];
|
||||
writeTrailer(trailer, 0);
|
||||
out.write(trailer);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes GZIP member header.
|
||||
*/
|
||||
private void writeHeader() throws IOException {
|
||||
out.write(new byte[] {
|
||||
(byte) GZIP_MAGIC, // Magic number (short)
|
||||
(byte)(GZIP_MAGIC >> 8), // Magic number (short)
|
||||
Deflater.DEFLATED, // Compression method (CM)
|
||||
0, // Flags (FLG)
|
||||
0, // Modification time MTIME (int)
|
||||
0, // Modification time MTIME (int)
|
||||
0, // Modification time MTIME (int)
|
||||
0, // Modification time MTIME (int)
|
||||
0, // Extra flags (XFLG)
|
||||
0 // Operating system (OS)
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes GZIP member trailer to a byte array, starting at a given
|
||||
* offset.
|
||||
*/
|
||||
private void writeTrailer(byte[] buf, int offset) throws IOException {
|
||||
writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data
|
||||
writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes integer in Intel byte order to a byte array, starting at a
|
||||
* given offset.
|
||||
*/
|
||||
private void writeInt(int i, byte[] buf, int offset) throws IOException {
|
||||
writeShort(i & 0xffff, buf, offset);
|
||||
writeShort((i >> 16) & 0xffff, buf, offset + 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes short integer in Intel byte order to a byte array, starting
|
||||
* at a given offset
|
||||
*/
|
||||
private void writeShort(int s, byte[] buf, int offset) throws IOException {
|
||||
buf[offset] = (byte)(s & 0xff);
|
||||
buf[offset + 1] = (byte)((s >> 8) & 0xff);
|
||||
}
|
||||
}
|
418
src/java.base/share/classes/java/util/zip/Inflater.java
Normal file
418
src/java.base/share/classes/java/util/zip/Inflater.java
Normal file
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/**
|
||||
* This class provides support for general purpose decompression using the
|
||||
* popular ZLIB compression library. The ZLIB compression library was
|
||||
* initially developed as part of the PNG graphics standard and is not
|
||||
* protected by patents. It is fully described in the specifications at
|
||||
* the <a href="package-summary.html#package.description">java.util.zip
|
||||
* package description</a>.
|
||||
*
|
||||
* <p>The following code fragment demonstrates a trivial compression
|
||||
* and decompression of a string using {@code Deflater} and
|
||||
* {@code Inflater}.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* try {
|
||||
* // Encode a String into bytes
|
||||
* String inputString = "blahblahblah\u20AC\u20AC";
|
||||
* byte[] input = inputString.getBytes("UTF-8");
|
||||
*
|
||||
* // Compress the bytes
|
||||
* byte[] output = new byte[100];
|
||||
* Deflater compresser = new Deflater();
|
||||
* compresser.setInput(input);
|
||||
* compresser.finish();
|
||||
* int compressedDataLength = compresser.deflate(output);
|
||||
*
|
||||
* // Decompress the bytes
|
||||
* Inflater decompresser = new Inflater();
|
||||
* decompresser.setInput(output, 0, compressedDataLength);
|
||||
* byte[] result = new byte[100];
|
||||
* int resultLength = decompresser.inflate(result);
|
||||
* decompresser.end();
|
||||
*
|
||||
* // Decode the bytes into a String
|
||||
* String outputString = new String(result, 0, resultLength, "UTF-8");
|
||||
* } catch(java.io.UnsupportedEncodingException ex) {
|
||||
* // handle
|
||||
* } catch (java.util.zip.DataFormatException ex) {
|
||||
* // handle
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @see Deflater
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*
|
||||
*/
|
||||
public
|
||||
class Inflater {
|
||||
|
||||
private final ZStreamRef zsRef;
|
||||
private byte[] buf = defaultBuf;
|
||||
private int off, len;
|
||||
private boolean finished;
|
||||
private boolean needDict;
|
||||
private long bytesRead;
|
||||
private long bytesWritten;
|
||||
|
||||
private static final byte[] defaultBuf = new byte[0];
|
||||
|
||||
static {
|
||||
ZipUtils.loadLibrary();
|
||||
initIDs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new decompressor. If the parameter 'nowrap' is true then
|
||||
* the ZLIB header and checksum fields will not be used. This provides
|
||||
* compatibility with the compression format used by both GZIP and PKZIP.
|
||||
* <p>
|
||||
* Note: When using the 'nowrap' option it is also necessary to provide
|
||||
* an extra "dummy" byte as input. This is required by the ZLIB native
|
||||
* library in order to support certain optimizations.
|
||||
*
|
||||
* @param nowrap if true then support GZIP compatible compression
|
||||
*/
|
||||
public Inflater(boolean nowrap) {
|
||||
zsRef = new ZStreamRef(init(nowrap));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new decompressor.
|
||||
*/
|
||||
public Inflater() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input data for decompression. Should be called whenever
|
||||
* needsInput() returns true indicating that more input data is
|
||||
* required.
|
||||
* @param b the input data bytes
|
||||
* @param off the start offset of the input data
|
||||
* @param len the length of the input data
|
||||
* @see Inflater#needsInput
|
||||
*/
|
||||
public void setInput(byte[] b, int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
this.buf = b;
|
||||
this.off = off;
|
||||
this.len = len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input data for decompression. Should be called whenever
|
||||
* needsInput() returns true indicating that more input data is
|
||||
* required.
|
||||
* @param b the input data bytes
|
||||
* @see Inflater#needsInput
|
||||
*/
|
||||
public void setInput(byte[] b) {
|
||||
setInput(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the preset dictionary to the given array of bytes. Should be
|
||||
* called when inflate() returns 0 and needsDictionary() returns true
|
||||
* indicating that a preset dictionary is required. The method getAdler()
|
||||
* can be used to get the Adler-32 value of the dictionary needed.
|
||||
* @param b the dictionary data bytes
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @see Inflater#needsDictionary
|
||||
* @see Inflater#getAdler
|
||||
*/
|
||||
public void setDictionary(byte[] b, int off, int len) {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
setDictionary(zsRef.address(), b, off, len);
|
||||
needDict = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the preset dictionary to the given array of bytes. Should be
|
||||
* called when inflate() returns 0 and needsDictionary() returns true
|
||||
* indicating that a preset dictionary is required. The method getAdler()
|
||||
* can be used to get the Adler-32 value of the dictionary needed.
|
||||
* @param b the dictionary data bytes
|
||||
* @see Inflater#needsDictionary
|
||||
* @see Inflater#getAdler
|
||||
*/
|
||||
public void setDictionary(byte[] b) {
|
||||
setDictionary(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of bytes remaining in the input buffer.
|
||||
* This can be used to find out what bytes still remain in the input
|
||||
* buffer after decompression has finished.
|
||||
* @return the total number of bytes remaining in the input buffer
|
||||
*/
|
||||
public int getRemaining() {
|
||||
synchronized (zsRef) {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if no data remains in the input buffer. This can
|
||||
* be used to determine if #setInput should be called in order
|
||||
* to provide more input.
|
||||
* @return true if no data remains in the input buffer
|
||||
*/
|
||||
public boolean needsInput() {
|
||||
synchronized (zsRef) {
|
||||
return len <= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a preset dictionary is needed for decompression.
|
||||
* @return true if a preset dictionary is needed for decompression
|
||||
* @see Inflater#setDictionary
|
||||
*/
|
||||
public boolean needsDictionary() {
|
||||
synchronized (zsRef) {
|
||||
return needDict;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the end of the compressed data stream has been
|
||||
* reached.
|
||||
* @return true if the end of the compressed data stream has been
|
||||
* reached
|
||||
*/
|
||||
public boolean finished() {
|
||||
synchronized (zsRef) {
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompresses bytes into specified buffer. Returns actual number
|
||||
* of bytes uncompressed. A return value of 0 indicates that
|
||||
* needsInput() or needsDictionary() should be called in order to
|
||||
* determine if more input data or a preset dictionary is required.
|
||||
* In the latter case, getAdler() can be used to get the Adler-32
|
||||
* value of the dictionary required.
|
||||
* @param b the buffer for the uncompressed data
|
||||
* @param off the start offset of the data
|
||||
* @param len the maximum number of uncompressed bytes
|
||||
* @return the actual number of uncompressed bytes
|
||||
* @exception DataFormatException if the compressed data format is invalid
|
||||
* @see Inflater#needsInput
|
||||
* @see Inflater#needsDictionary
|
||||
*/
|
||||
public int inflate(byte[] b, int off, int len)
|
||||
throws DataFormatException
|
||||
{
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
int thisLen = this.len;
|
||||
int n = inflateBytes(zsRef.address(), b, off, len);
|
||||
bytesWritten += n;
|
||||
bytesRead += (thisLen - this.len);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompresses bytes into specified buffer. Returns actual number
|
||||
* of bytes uncompressed. A return value of 0 indicates that
|
||||
* needsInput() or needsDictionary() should be called in order to
|
||||
* determine if more input data or a preset dictionary is required.
|
||||
* In the latter case, getAdler() can be used to get the Adler-32
|
||||
* value of the dictionary required.
|
||||
* @param b the buffer for the uncompressed data
|
||||
* @return the actual number of uncompressed bytes
|
||||
* @exception DataFormatException if the compressed data format is invalid
|
||||
* @see Inflater#needsInput
|
||||
* @see Inflater#needsDictionary
|
||||
*/
|
||||
public int inflate(byte[] b) throws DataFormatException {
|
||||
return inflate(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ADLER-32 value of the uncompressed data.
|
||||
* @return the ADLER-32 value of the uncompressed data
|
||||
*/
|
||||
public int getAdler() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
return getAdler(zsRef.address());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of compressed bytes input so far.
|
||||
*
|
||||
* <p>Since the number of bytes may be greater than
|
||||
* Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
|
||||
* the preferred means of obtaining this information.</p>
|
||||
*
|
||||
* @return the total number of compressed bytes input so far
|
||||
*/
|
||||
public int getTotalIn() {
|
||||
return (int) getBytesRead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of compressed bytes input so far.
|
||||
*
|
||||
* @return the total (non-negative) number of compressed bytes input so far
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesRead() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of uncompressed bytes output so far.
|
||||
*
|
||||
* <p>Since the number of bytes may be greater than
|
||||
* Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
|
||||
* the preferred means of obtaining this information.</p>
|
||||
*
|
||||
* @return the total number of uncompressed bytes output so far
|
||||
*/
|
||||
public int getTotalOut() {
|
||||
return (int) getBytesWritten();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of uncompressed bytes output so far.
|
||||
*
|
||||
* @return the total (non-negative) number of uncompressed bytes output so far
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesWritten() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
return bytesWritten;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets inflater so that a new set of input data can be processed.
|
||||
*/
|
||||
public void reset() {
|
||||
synchronized (zsRef) {
|
||||
ensureOpen();
|
||||
reset(zsRef.address());
|
||||
buf = defaultBuf;
|
||||
finished = false;
|
||||
needDict = false;
|
||||
off = len = 0;
|
||||
bytesRead = bytesWritten = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the decompressor and discards any unprocessed input.
|
||||
* This method should be called when the decompressor is no longer
|
||||
* being used, but will also be called automatically by the finalize()
|
||||
* method. Once this method is called, the behavior of the Inflater
|
||||
* object is undefined.
|
||||
*/
|
||||
public void end() {
|
||||
synchronized (zsRef) {
|
||||
long addr = zsRef.address();
|
||||
zsRef.clear();
|
||||
if (addr != 0) {
|
||||
end(addr);
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the decompressor when garbage is collected.
|
||||
*
|
||||
* @deprecated The {@code finalize} method has been deprecated.
|
||||
* Subclasses that override {@code finalize} in order to perform cleanup
|
||||
* should be modified to use alternative cleanup mechanisms and
|
||||
* to remove the overriding {@code finalize} method.
|
||||
* When overriding the {@code finalize} method, its implementation must explicitly
|
||||
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
|
||||
* See the specification for {@link Object#finalize()} for further
|
||||
* information about migration options.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
protected void finalize() {
|
||||
end();
|
||||
}
|
||||
|
||||
private void ensureOpen () {
|
||||
assert Thread.holdsLock(zsRef);
|
||||
if (zsRef.address() == 0)
|
||||
throw new NullPointerException("Inflater has been closed");
|
||||
}
|
||||
|
||||
boolean ended() {
|
||||
synchronized (zsRef) {
|
||||
return zsRef.address() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
private static native long init(boolean nowrap);
|
||||
private static native void setDictionary(long addr, byte[] b, int off,
|
||||
int len);
|
||||
private native int inflateBytes(long addr, byte[] b, int off, int len)
|
||||
throws DataFormatException;
|
||||
private static native int getAdler(long addr);
|
||||
private static native void reset(long addr);
|
||||
private static native void end(long addr);
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
|
||||
/**
|
||||
* This class implements a stream filter for uncompressing data in the
|
||||
* "deflate" compression format. It is also used as the basis for other
|
||||
* decompression filters, such as GZIPInputStream.
|
||||
*
|
||||
* @see Inflater
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class InflaterInputStream extends FilterInputStream {
|
||||
/**
|
||||
* Decompressor for this stream.
|
||||
*/
|
||||
protected Inflater inf;
|
||||
|
||||
/**
|
||||
* Input buffer for decompression.
|
||||
*/
|
||||
protected byte[] buf;
|
||||
|
||||
/**
|
||||
* Length of input buffer.
|
||||
*/
|
||||
protected int len;
|
||||
|
||||
private boolean closed = false;
|
||||
// this flag is set to true after EOF has reached
|
||||
private boolean reachEOF = false;
|
||||
|
||||
/**
|
||||
* Check to make sure that this stream has not been closed
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new input stream with the specified decompressor and
|
||||
* buffer size.
|
||||
* @param in the input stream
|
||||
* @param inf the decompressor ("inflater")
|
||||
* @param size the input buffer size
|
||||
* @exception IllegalArgumentException if {@code size <= 0}
|
||||
*/
|
||||
public InflaterInputStream(InputStream in, Inflater inf, int size) {
|
||||
super(in);
|
||||
if (in == null || inf == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (size <= 0) {
|
||||
throw new IllegalArgumentException("buffer size <= 0");
|
||||
}
|
||||
this.inf = inf;
|
||||
buf = new byte[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input stream with the specified decompressor and a
|
||||
* default buffer size.
|
||||
* @param in the input stream
|
||||
* @param inf the decompressor ("inflater")
|
||||
*/
|
||||
public InflaterInputStream(InputStream in, Inflater inf) {
|
||||
this(in, inf, 512);
|
||||
}
|
||||
|
||||
boolean usesDefaultInflater = false;
|
||||
|
||||
/**
|
||||
* Creates a new input stream with a default decompressor and buffer size.
|
||||
* @param in the input stream
|
||||
*/
|
||||
public InflaterInputStream(InputStream in) {
|
||||
this(in, new Inflater());
|
||||
usesDefaultInflater = true;
|
||||
}
|
||||
|
||||
private byte[] singleByteBuf = new byte[1];
|
||||
|
||||
/**
|
||||
* Reads a byte of uncompressed data. This method will block until
|
||||
* enough input is available for decompression.
|
||||
* @return the byte read, or -1 if end of compressed input is reached
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
ensureOpen();
|
||||
return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads uncompressed data into an array of bytes. If <code>len</code> is not
|
||||
* zero, the method will block until some input can be decompressed; otherwise,
|
||||
* no bytes are read and <code>0</code> is returned.
|
||||
* @param b the buffer into which the data is read
|
||||
* @param off the start offset in the destination array <code>b</code>
|
||||
* @param len the maximum number of bytes read
|
||||
* @return the actual number of bytes read, or -1 if the end of the
|
||||
* compressed input is reached or a preset dictionary is needed
|
||||
* @exception NullPointerException If <code>b</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
|
||||
* <code>len</code> is negative, or <code>len</code> is greater than
|
||||
* <code>b.length - off</code>
|
||||
* @exception ZipException if a ZIP format error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
int n;
|
||||
while ((n = inf.inflate(b, off, len)) == 0) {
|
||||
if (inf.finished() || inf.needsDictionary()) {
|
||||
reachEOF = true;
|
||||
return -1;
|
||||
}
|
||||
if (inf.needsInput()) {
|
||||
fill();
|
||||
}
|
||||
}
|
||||
return n;
|
||||
} catch (DataFormatException e) {
|
||||
String s = e.getMessage();
|
||||
throw new ZipException(s != null ? s : "Invalid ZLIB data format");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 after EOF has been reached, otherwise always return 1.
|
||||
* <p>
|
||||
* Programs should not count on this method to return the actual number
|
||||
* of bytes that could be read without blocking.
|
||||
*
|
||||
* @return 1 before EOF and 0 after EOF.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
ensureOpen();
|
||||
if (reachEOF) {
|
||||
return 0;
|
||||
} else if (inf.finished()) {
|
||||
// the end of the compressed data stream has been reached
|
||||
reachEOF = true;
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] b = new byte[512];
|
||||
|
||||
/**
|
||||
* Skips specified number of bytes of uncompressed data.
|
||||
* @param n the number of bytes to skip
|
||||
* @return the actual number of bytes skipped.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
* @exception IllegalArgumentException if {@code n < 0}
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("negative skip length");
|
||||
}
|
||||
ensureOpen();
|
||||
int max = (int)Math.min(n, Integer.MAX_VALUE);
|
||||
int total = 0;
|
||||
while (total < max) {
|
||||
int len = max - total;
|
||||
if (len > b.length) {
|
||||
len = b.length;
|
||||
}
|
||||
len = read(b, 0, len);
|
||||
if (len == -1) {
|
||||
reachEOF = true;
|
||||
break;
|
||||
}
|
||||
total += len;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources associated
|
||||
* with the stream.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed) {
|
||||
if (usesDefaultInflater)
|
||||
inf.end();
|
||||
in.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills input buffer with more data to decompress.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
protected void fill() throws IOException {
|
||||
ensureOpen();
|
||||
len = in.read(buf, 0, buf.length);
|
||||
if (len == -1) {
|
||||
throw new EOFException("Unexpected end of ZLIB input stream");
|
||||
}
|
||||
inf.setInput(buf, 0, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this input stream supports the <code>mark</code> and
|
||||
* <code>reset</code> methods. The <code>markSupported</code>
|
||||
* method of <code>InflaterInputStream</code> returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating if this stream type supports
|
||||
* the <code>mark</code> and <code>reset</code> methods.
|
||||
* @see java.io.InputStream#mark(int)
|
||||
* @see java.io.InputStream#reset()
|
||||
*/
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current position in this input stream.
|
||||
*
|
||||
* <p> The <code>mark</code> method of <code>InflaterInputStream</code>
|
||||
* does nothing.
|
||||
*
|
||||
* @param readlimit the maximum limit of bytes that can be read before
|
||||
* the mark position becomes invalid.
|
||||
* @see java.io.InputStream#reset()
|
||||
*/
|
||||
public synchronized void mark(int readlimit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Repositions this stream to the position at the time the
|
||||
* <code>mark</code> method was last called on this input stream.
|
||||
*
|
||||
* <p> The method <code>reset</code> for class
|
||||
* <code>InflaterInputStream</code> does nothing except throw an
|
||||
* <code>IOException</code>.
|
||||
*
|
||||
* @exception IOException if this method is invoked.
|
||||
* @see java.io.InputStream#mark(int)
|
||||
* @see java.io.IOException
|
||||
*/
|
||||
public synchronized void reset() throws IOException {
|
||||
throw new IOException("mark/reset not supported");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Implements an output stream filter for uncompressing data stored in the
|
||||
* "deflate" compression format.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author David R Tribble (david@tribble.com)
|
||||
*
|
||||
* @see InflaterInputStream
|
||||
* @see DeflaterInputStream
|
||||
* @see DeflaterOutputStream
|
||||
*/
|
||||
|
||||
public class InflaterOutputStream extends FilterOutputStream {
|
||||
/** Decompressor for this stream. */
|
||||
protected final Inflater inf;
|
||||
|
||||
/** Output buffer for writing uncompressed data. */
|
||||
protected final byte[] buf;
|
||||
|
||||
/** Temporary write buffer. */
|
||||
private final byte[] wbuf = new byte[1];
|
||||
|
||||
/** Default decompressor is used. */
|
||||
private boolean usesDefaultInflater = false;
|
||||
|
||||
/** true iff {@link #close()} has been called. */
|
||||
private boolean closed = false;
|
||||
|
||||
/**
|
||||
* Checks to make sure that this stream has not been closed.
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with a default decompressor and buffer
|
||||
* size.
|
||||
*
|
||||
* @param out output stream to write the uncompressed data to
|
||||
* @throws NullPointerException if {@code out} is null
|
||||
*/
|
||||
public InflaterOutputStream(OutputStream out) {
|
||||
this(out, new Inflater());
|
||||
usesDefaultInflater = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified decompressor and a
|
||||
* default buffer size.
|
||||
*
|
||||
* @param out output stream to write the uncompressed data to
|
||||
* @param infl decompressor ("inflater") for this stream
|
||||
* @throws NullPointerException if {@code out} or {@code infl} is null
|
||||
*/
|
||||
public InflaterOutputStream(OutputStream out, Inflater infl) {
|
||||
this(out, infl, 512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new output stream with the specified decompressor and
|
||||
* buffer size.
|
||||
*
|
||||
* @param out output stream to write the uncompressed data to
|
||||
* @param infl decompressor ("inflater") for this stream
|
||||
* @param bufLen decompression buffer size
|
||||
* @throws IllegalArgumentException if {@code bufLen <= 0}
|
||||
* @throws NullPointerException if {@code out} or {@code infl} is null
|
||||
*/
|
||||
public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) {
|
||||
super(out);
|
||||
|
||||
// Sanity checks
|
||||
if (out == null)
|
||||
throw new NullPointerException("Null output");
|
||||
if (infl == null)
|
||||
throw new NullPointerException("Null inflater");
|
||||
if (bufLen <= 0)
|
||||
throw new IllegalArgumentException("Buffer size < 1");
|
||||
|
||||
// Initialize
|
||||
inf = infl;
|
||||
buf = new byte[bufLen];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes any remaining uncompressed data to the output stream and closes
|
||||
* the underlying output stream.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed) {
|
||||
// Complete the uncompressed output
|
||||
try {
|
||||
finish();
|
||||
} finally {
|
||||
out.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes this output stream, forcing any pending buffered output bytes to be
|
||||
* written.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs or this stream is already
|
||||
* closed
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
ensureOpen();
|
||||
|
||||
// Finish decompressing and writing pending output data
|
||||
if (!inf.finished()) {
|
||||
try {
|
||||
while (!inf.finished() && !inf.needsInput()) {
|
||||
int n;
|
||||
|
||||
// Decompress pending output data
|
||||
n = inf.inflate(buf, 0, buf.length);
|
||||
if (n < 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Write the uncompressed output data block
|
||||
out.write(buf, 0, n);
|
||||
}
|
||||
super.flush();
|
||||
} catch (DataFormatException ex) {
|
||||
// Improperly formatted compressed (ZIP) data
|
||||
String msg = ex.getMessage();
|
||||
if (msg == null) {
|
||||
msg = "Invalid ZLIB data format";
|
||||
}
|
||||
throw new ZipException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes writing uncompressed data to the output stream without closing
|
||||
* the underlying stream. Use this method when applying multiple filters in
|
||||
* succession to the same output stream.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs or this stream is already
|
||||
* closed
|
||||
*/
|
||||
public void finish() throws IOException {
|
||||
ensureOpen();
|
||||
|
||||
// Finish decompressing and writing pending output data
|
||||
flush();
|
||||
if (usesDefaultInflater) {
|
||||
inf.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the uncompressed output stream.
|
||||
*
|
||||
* @param b a single byte of compressed data to decompress and write to
|
||||
* the output stream
|
||||
* @throws IOException if an I/O error occurs or this stream is already
|
||||
* closed
|
||||
* @throws ZipException if a compression (ZIP) format error occurs
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
// Write a single byte of data
|
||||
wbuf[0] = (byte) b;
|
||||
write(wbuf, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes to the uncompressed output stream.
|
||||
*
|
||||
* @param b buffer containing compressed data to decompress and write to
|
||||
* the output stream
|
||||
* @param off starting offset of the compressed data within {@code b}
|
||||
* @param len number of bytes to decompress from {@code b}
|
||||
* @throws IndexOutOfBoundsException if {@code off < 0}, or if
|
||||
* {@code len < 0}, or if {@code len > b.length - off}
|
||||
* @throws IOException if an I/O error occurs or this stream is already
|
||||
* closed
|
||||
* @throws NullPointerException if {@code b} is null
|
||||
* @throws ZipException if a compression (ZIP) format error occurs
|
||||
*/
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
// Sanity checks
|
||||
ensureOpen();
|
||||
if (b == null) {
|
||||
throw new NullPointerException("Null buffer for read");
|
||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Write uncompressed data to the output stream
|
||||
try {
|
||||
for (;;) {
|
||||
int n;
|
||||
|
||||
// Fill the decompressor buffer with output data
|
||||
if (inf.needsInput()) {
|
||||
int part;
|
||||
|
||||
if (len < 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = (len < 512 ? len : 512);
|
||||
inf.setInput(b, off, part);
|
||||
off += part;
|
||||
len -= part;
|
||||
}
|
||||
|
||||
// Decompress and write blocks of output data
|
||||
do {
|
||||
n = inf.inflate(buf, 0, buf.length);
|
||||
if (n > 0) {
|
||||
out.write(buf, 0, n);
|
||||
}
|
||||
} while (n > 0);
|
||||
|
||||
// Check the decompressor
|
||||
if (inf.finished()) {
|
||||
break;
|
||||
}
|
||||
if (inf.needsDictionary()) {
|
||||
throw new ZipException("ZLIB dictionary missing");
|
||||
}
|
||||
}
|
||||
} catch (DataFormatException ex) {
|
||||
// Improperly formatted compressed (ZIP) data
|
||||
String msg = ex.getMessage();
|
||||
if (msg == null) {
|
||||
msg = "Invalid ZLIB data format";
|
||||
}
|
||||
throw new ZipException(msg);
|
||||
}
|
||||
}
|
||||
}
|
46
src/java.base/share/classes/java/util/zip/ZStreamRef.java
Normal file
46
src/java.base/share/classes/java/util/zip/ZStreamRef.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/**
|
||||
* A reference to the native zlib's z_stream structure.
|
||||
*/
|
||||
|
||||
class ZStreamRef {
|
||||
|
||||
private volatile long address;
|
||||
ZStreamRef (long address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
long address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
address = 0;
|
||||
}
|
||||
}
|
166
src/java.base/share/classes/java/util/zip/ZipCoder.java
Normal file
166
src/java.base/share/classes/java/util/zip/ZipCoder.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.Arrays;
|
||||
import sun.nio.cs.ArrayDecoder;
|
||||
import sun.nio.cs.ArrayEncoder;
|
||||
|
||||
/**
|
||||
* Utility class for zipfile name and comment decoding and encoding
|
||||
*/
|
||||
|
||||
final class ZipCoder {
|
||||
|
||||
String toString(byte[] ba, int off, int length) {
|
||||
CharsetDecoder cd = decoder().reset();
|
||||
int len = (int)(length * cd.maxCharsPerByte());
|
||||
char[] ca = new char[len];
|
||||
if (len == 0)
|
||||
return new String(ca);
|
||||
// UTF-8 only for now. Other ArrayDeocder only handles
|
||||
// CodingErrorAction.REPLACE mode. ZipCoder uses
|
||||
// REPORT mode.
|
||||
if (isUTF8 && cd instanceof ArrayDecoder) {
|
||||
int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca);
|
||||
if (clen == -1) // malformed
|
||||
throw new IllegalArgumentException("MALFORMED");
|
||||
return new String(ca, 0, clen);
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, off, length);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
return new String(ca, 0, cb.position());
|
||||
}
|
||||
|
||||
String toString(byte[] ba, int length) {
|
||||
return toString(ba, 0, length);
|
||||
}
|
||||
|
||||
String toString(byte[] ba) {
|
||||
return toString(ba, 0, ba.length);
|
||||
}
|
||||
|
||||
byte[] getBytes(String s) {
|
||||
CharsetEncoder ce = encoder().reset();
|
||||
char[] ca = s.toCharArray();
|
||||
int len = (int)(ca.length * ce.maxBytesPerChar());
|
||||
byte[] ba = new byte[len];
|
||||
if (len == 0)
|
||||
return ba;
|
||||
// UTF-8 only for now. Other ArrayDeocder only handles
|
||||
// CodingErrorAction.REPLACE mode.
|
||||
if (isUTF8 && ce instanceof ArrayEncoder) {
|
||||
int blen = ((ArrayEncoder)ce).encode(ca, 0, ca.length, ba);
|
||||
if (blen == -1) // malformed
|
||||
throw new IllegalArgumentException("MALFORMED");
|
||||
return Arrays.copyOf(ba, blen);
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
if (bb.position() == ba.length) // defensive copy?
|
||||
return ba;
|
||||
else
|
||||
return Arrays.copyOf(ba, bb.position());
|
||||
}
|
||||
|
||||
// assume invoked only if "this" is not utf8
|
||||
byte[] getBytesUTF8(String s) {
|
||||
if (isUTF8)
|
||||
return getBytes(s);
|
||||
if (utf8 == null)
|
||||
utf8 = new ZipCoder(StandardCharsets.UTF_8);
|
||||
return utf8.getBytes(s);
|
||||
}
|
||||
|
||||
String toStringUTF8(byte[] ba, int len) {
|
||||
return toStringUTF8(ba, 0, len);
|
||||
}
|
||||
|
||||
String toStringUTF8(byte[] ba, int off, int len) {
|
||||
if (isUTF8)
|
||||
return toString(ba, off, len);
|
||||
if (utf8 == null)
|
||||
utf8 = new ZipCoder(StandardCharsets.UTF_8);
|
||||
return utf8.toString(ba, off, len);
|
||||
}
|
||||
|
||||
boolean isUTF8() {
|
||||
return isUTF8;
|
||||
}
|
||||
|
||||
private Charset cs;
|
||||
private CharsetDecoder dec;
|
||||
private CharsetEncoder enc;
|
||||
private boolean isUTF8;
|
||||
private ZipCoder utf8;
|
||||
|
||||
private ZipCoder(Charset cs) {
|
||||
this.cs = cs;
|
||||
this.isUTF8 = cs.name().equals(StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
static ZipCoder get(Charset charset) {
|
||||
return new ZipCoder(charset);
|
||||
}
|
||||
|
||||
private CharsetDecoder decoder() {
|
||||
if (dec == null) {
|
||||
dec = cs.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
}
|
||||
return dec;
|
||||
}
|
||||
|
||||
private CharsetEncoder encoder() {
|
||||
if (enc == null) {
|
||||
enc = cs.newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
}
|
99
src/java.base/share/classes/java/util/zip/ZipConstants.java
Normal file
99
src/java.base/share/classes/java/util/zip/ZipConstants.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/*
|
||||
* This interface defines the constants that are used by the classes
|
||||
* which manipulate ZIP files.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
interface ZipConstants {
|
||||
/*
|
||||
* Header signatures
|
||||
*/
|
||||
static long LOCSIG = 0x04034b50L; // "PK\003\004"
|
||||
static long EXTSIG = 0x08074b50L; // "PK\007\008"
|
||||
static long CENSIG = 0x02014b50L; // "PK\001\002"
|
||||
static long ENDSIG = 0x06054b50L; // "PK\005\006"
|
||||
|
||||
/*
|
||||
* Header sizes in bytes (including signatures)
|
||||
*/
|
||||
static final int LOCHDR = 30; // LOC header size
|
||||
static final int EXTHDR = 16; // EXT header size
|
||||
static final int CENHDR = 46; // CEN header size
|
||||
static final int ENDHDR = 22; // END header size
|
||||
|
||||
/*
|
||||
* Local file (LOC) header field offsets
|
||||
*/
|
||||
static final int LOCVER = 4; // version needed to extract
|
||||
static final int LOCFLG = 6; // general purpose bit flag
|
||||
static final int LOCHOW = 8; // compression method
|
||||
static final int LOCTIM = 10; // modification time
|
||||
static final int LOCCRC = 14; // uncompressed file crc-32 value
|
||||
static final int LOCSIZ = 18; // compressed size
|
||||
static final int LOCLEN = 22; // uncompressed size
|
||||
static final int LOCNAM = 26; // filename length
|
||||
static final int LOCEXT = 28; // extra field length
|
||||
|
||||
/*
|
||||
* Extra local (EXT) header field offsets
|
||||
*/
|
||||
static final int EXTCRC = 4; // uncompressed file crc-32 value
|
||||
static final int EXTSIZ = 8; // compressed size
|
||||
static final int EXTLEN = 12; // uncompressed size
|
||||
|
||||
/*
|
||||
* Central directory (CEN) header field offsets
|
||||
*/
|
||||
static final int CENVEM = 4; // version made by
|
||||
static final int CENVER = 6; // version needed to extract
|
||||
static final int CENFLG = 8; // encrypt, decrypt flags
|
||||
static final int CENHOW = 10; // compression method
|
||||
static final int CENTIM = 12; // modification time
|
||||
static final int CENCRC = 16; // uncompressed file crc-32 value
|
||||
static final int CENSIZ = 20; // compressed size
|
||||
static final int CENLEN = 24; // uncompressed size
|
||||
static final int CENNAM = 28; // filename length
|
||||
static final int CENEXT = 30; // extra field length
|
||||
static final int CENCOM = 32; // comment length
|
||||
static final int CENDSK = 34; // disk number start
|
||||
static final int CENATT = 36; // internal file attributes
|
||||
static final int CENATX = 38; // external file attributes
|
||||
static final int CENOFF = 42; // LOC header offset
|
||||
|
||||
/*
|
||||
* End of central directory (END) header field offsets
|
||||
*/
|
||||
static final int ENDSUB = 8; // number of entries on this disk
|
||||
static final int ENDTOT = 10; // total number of entries
|
||||
static final int ENDSIZ = 12; // central directory size in bytes
|
||||
static final int ENDOFF = 16; // offset of first CEN header
|
||||
static final int ENDCOM = 20; // zip file comment length
|
||||
}
|
105
src/java.base/share/classes/java/util/zip/ZipConstants64.java
Normal file
105
src/java.base/share/classes/java/util/zip/ZipConstants64.java
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/*
|
||||
* This class defines the constants that are used by the classes
|
||||
* which manipulate Zip64 files.
|
||||
*/
|
||||
|
||||
class ZipConstants64 {
|
||||
|
||||
/*
|
||||
* ZIP64 constants
|
||||
*/
|
||||
static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006"
|
||||
static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007"
|
||||
static final int ZIP64_ENDHDR = 56; // ZIP64 end header size
|
||||
static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size
|
||||
static final int ZIP64_EXTHDR = 24; // EXT header size
|
||||
static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID
|
||||
|
||||
static final int ZIP64_MAGICCOUNT = 0xFFFF;
|
||||
static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
|
||||
|
||||
/*
|
||||
* Zip64 End of central directory (END) header field offsets
|
||||
*/
|
||||
static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir
|
||||
static final int ZIP64_ENDVEM = 12; // version made by
|
||||
static final int ZIP64_ENDVER = 14; // version needed to extract
|
||||
static final int ZIP64_ENDNMD = 16; // number of this disk
|
||||
static final int ZIP64_ENDDSK = 20; // disk number of start
|
||||
static final int ZIP64_ENDTOD = 24; // total number of entries on this disk
|
||||
static final int ZIP64_ENDTOT = 32; // total number of entries
|
||||
static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
|
||||
static final int ZIP64_ENDOFF = 48; // offset of first CEN header
|
||||
static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector
|
||||
|
||||
/*
|
||||
* Zip64 End of central directory locator field offsets
|
||||
*/
|
||||
static final int ZIP64_LOCDSK = 4; // disk number start
|
||||
static final int ZIP64_LOCOFF = 8; // offset of zip64 end
|
||||
static final int ZIP64_LOCTOT = 16; // total number of disks
|
||||
|
||||
/*
|
||||
* Zip64 Extra local (EXT) header field offsets
|
||||
*/
|
||||
static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value
|
||||
static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte
|
||||
static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte
|
||||
|
||||
/*
|
||||
* Language encoding flag EFS
|
||||
*/
|
||||
static final int EFS = 0x800; // If this bit is set the filename and
|
||||
// comment fields for this file must be
|
||||
// encoded using UTF-8.
|
||||
|
||||
/*
|
||||
* Constants below are defined here (instead of in ZipConstants)
|
||||
* to avoid being exposed as public fields of ZipFile, ZipEntry,
|
||||
* ZipInputStream and ZipOutputstream.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Extra field header ID
|
||||
*/
|
||||
static final int EXTID_ZIP64 = 0x0001; // Zip64
|
||||
static final int EXTID_NTFS = 0x000a; // NTFS
|
||||
static final int EXTID_UNIX = 0x000d; // UNIX
|
||||
static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
|
||||
|
||||
/*
|
||||
* EXTT timestamp flags
|
||||
*/
|
||||
static final int EXTT_FLAG_LMT = 0x1; // LastModifiedTime
|
||||
static final int EXTT_FLAG_LAT = 0x2; // LastAccessTime
|
||||
static final int EXTT_FLAT_CT = 0x4; // CreationTime
|
||||
|
||||
private ZipConstants64() {}
|
||||
}
|
686
src/java.base/share/classes/java/util/zip/ZipEntry.java
Normal file
686
src/java.base/share/classes/java/util/zip/ZipEntry.java
Normal file
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import static java.util.zip.ZipUtils.*;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.ZoneId;
|
||||
|
||||
import static java.util.zip.ZipConstants64.*;
|
||||
|
||||
/**
|
||||
* This class is used to represent a ZIP file entry.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class ZipEntry implements ZipConstants, Cloneable {
|
||||
|
||||
String name; // entry name
|
||||
long xdostime = -1; // last modification time (in extended DOS time,
|
||||
// where milliseconds lost in conversion might
|
||||
// be encoded into the upper half)
|
||||
FileTime mtime; // last modification time, from extra field data
|
||||
FileTime atime; // last access time, from extra field data
|
||||
FileTime ctime; // creation time, from extra field data
|
||||
long crc = -1; // crc-32 of entry data
|
||||
long size = -1; // uncompressed size of entry data
|
||||
long csize = -1; // compressed size of entry data
|
||||
int method = -1; // compression method
|
||||
int flag = 0; // general purpose flag
|
||||
byte[] extra; // optional extra field data for entry
|
||||
String comment; // optional comment string for entry
|
||||
|
||||
/**
|
||||
* Compression method for uncompressed entries.
|
||||
*/
|
||||
public static final int STORED = 0;
|
||||
|
||||
/**
|
||||
* Compression method for compressed (deflated) entries.
|
||||
*/
|
||||
public static final int DEFLATED = 8;
|
||||
|
||||
/**
|
||||
* DOS time constant for representing timestamps before 1980.
|
||||
*/
|
||||
static final long DOSTIME_BEFORE_1980 = (1 << 21) | (1 << 16);
|
||||
|
||||
/**
|
||||
* Approximately 128 years, in milliseconds (ignoring leap years etc).
|
||||
*
|
||||
* This establish an approximate high-bound value for DOS times in
|
||||
* milliseconds since epoch, used to enable an efficient but
|
||||
* sufficient bounds check to avoid generating extended last modified
|
||||
* time entries.
|
||||
*
|
||||
* Calculating the exact number is locale dependent, would require loading
|
||||
* TimeZone data eagerly, and would make little practical sense. Since DOS
|
||||
* times theoretically go to 2107 - with compatibility not guaranteed
|
||||
* after 2099 - setting this to a time that is before but near 2099
|
||||
* should be sufficient.
|
||||
*/
|
||||
private static final long UPPER_DOSTIME_BOUND =
|
||||
128L * 365 * 24 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* Creates a new zip entry with the specified name.
|
||||
*
|
||||
* @param name
|
||||
* The entry name
|
||||
*
|
||||
* @throws NullPointerException if the entry name is null
|
||||
* @throws IllegalArgumentException if the entry name is longer than
|
||||
* 0xFFFF bytes
|
||||
*/
|
||||
public ZipEntry(String name) {
|
||||
Objects.requireNonNull(name, "name");
|
||||
if (name.length() > 0xFFFF) {
|
||||
throw new IllegalArgumentException("entry name too long");
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new zip entry with fields taken from the specified
|
||||
* zip entry.
|
||||
*
|
||||
* @param e
|
||||
* A zip Entry object
|
||||
*
|
||||
* @throws NullPointerException if the entry object is null
|
||||
*/
|
||||
public ZipEntry(ZipEntry e) {
|
||||
Objects.requireNonNull(e, "entry");
|
||||
name = e.name;
|
||||
xdostime = e.xdostime;
|
||||
mtime = e.mtime;
|
||||
atime = e.atime;
|
||||
ctime = e.ctime;
|
||||
crc = e.crc;
|
||||
size = e.size;
|
||||
csize = e.csize;
|
||||
method = e.method;
|
||||
flag = e.flag;
|
||||
extra = e.extra;
|
||||
comment = e.comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new un-initialized zip entry
|
||||
*/
|
||||
ZipEntry() {}
|
||||
|
||||
/**
|
||||
* Returns the name of the entry.
|
||||
* @return the name of the entry
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last modification time of the entry.
|
||||
*
|
||||
* <p> If the entry is output to a ZIP file or ZIP file formatted
|
||||
* output stream the last modification time set by this method will
|
||||
* be stored into the {@code date and time fields} of the zip file
|
||||
* entry and encoded in standard {@code MS-DOS date and time format}.
|
||||
* The {@link java.util.TimeZone#getDefault() default TimeZone} is
|
||||
* used to convert the epoch time to the MS-DOS data and time.
|
||||
*
|
||||
* @param time
|
||||
* The last modification time of the entry in milliseconds
|
||||
* since the epoch
|
||||
*
|
||||
* @see #getTime()
|
||||
* @see #getLastModifiedTime()
|
||||
*/
|
||||
public void setTime(long time) {
|
||||
this.xdostime = javaToExtendedDosTime(time);
|
||||
// Avoid setting the mtime field if time is in the valid
|
||||
// range for a DOS time
|
||||
if (xdostime != DOSTIME_BEFORE_1980 && time <= UPPER_DOSTIME_BOUND) {
|
||||
this.mtime = null;
|
||||
} else {
|
||||
this.mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification time of the entry.
|
||||
*
|
||||
* <p> If the entry is read from a ZIP file or ZIP file formatted
|
||||
* input stream, this is the last modification time from the {@code
|
||||
* date and time fields} of the zip file entry. The
|
||||
* {@link java.util.TimeZone#getDefault() default TimeZone} is used
|
||||
* to convert the standard MS-DOS formatted date and time to the
|
||||
* epoch time.
|
||||
*
|
||||
* @return The last modification time of the entry in milliseconds
|
||||
* since the epoch, or -1 if not specified
|
||||
*
|
||||
* @see #setTime(long)
|
||||
* @see #setLastModifiedTime(FileTime)
|
||||
*/
|
||||
public long getTime() {
|
||||
if (mtime != null) {
|
||||
return mtime.toMillis();
|
||||
}
|
||||
return (xdostime != -1) ? extendedDosToJavaTime(xdostime) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last modification time of the entry in local date-time.
|
||||
*
|
||||
* <p> If the entry is output to a ZIP file or ZIP file formatted
|
||||
* output stream the last modification time set by this method will
|
||||
* be stored into the {@code date and time fields} of the zip file
|
||||
* entry and encoded in standard {@code MS-DOS date and time format}.
|
||||
* If the date-time set is out of the range of the standard {@code
|
||||
* MS-DOS date and time format}, the time will also be stored into
|
||||
* zip file entry's extended timestamp fields in {@code optional
|
||||
* extra data} in UTC time. The {@link java.time.ZoneId#systemDefault()
|
||||
* system default TimeZone} is used to convert the local date-time
|
||||
* to UTC time.
|
||||
*
|
||||
* <p> {@code LocalDateTime} uses a precision of nanoseconds, whereas
|
||||
* this class uses a precision of milliseconds. The conversion will
|
||||
* truncate any excess precision information as though the amount in
|
||||
* nanoseconds was subject to integer division by one million.
|
||||
*
|
||||
* @param time
|
||||
* The last modification time of the entry in local date-time
|
||||
*
|
||||
* @see #getTimeLocal()
|
||||
* @since 9
|
||||
*/
|
||||
public void setTimeLocal(LocalDateTime time) {
|
||||
int year = time.getYear() - 1980;
|
||||
if (year < 0) {
|
||||
this.xdostime = DOSTIME_BEFORE_1980;
|
||||
} else {
|
||||
this.xdostime = ((year << 25 |
|
||||
time.getMonthValue() << 21 |
|
||||
time.getDayOfMonth() << 16 |
|
||||
time.getHour() << 11 |
|
||||
time.getMinute() << 5 |
|
||||
time.getSecond() >> 1) & 0xffffffffL)
|
||||
+ ((long)(((time.getSecond() & 0x1) * 1000) +
|
||||
time.getNano() / 1000_000) << 32);
|
||||
}
|
||||
if (xdostime != DOSTIME_BEFORE_1980 && year <= 0x7f) {
|
||||
this.mtime = null;
|
||||
} else {
|
||||
this.mtime = FileTime.from(
|
||||
ZonedDateTime.of(time, ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification time of the entry in local date-time.
|
||||
*
|
||||
* <p> If the entry is read from a ZIP file or ZIP file formatted
|
||||
* input stream, this is the last modification time from the zip
|
||||
* file entry's {@code optional extra data} if the extended timestamp
|
||||
* fields are present. Otherwise, the last modification time is read
|
||||
* from entry's standard MS-DOS formatted {@code date and time fields}.
|
||||
*
|
||||
* <p> The {@link java.time.ZoneId#systemDefault() system default TimeZone}
|
||||
* is used to convert the UTC time to local date-time.
|
||||
*
|
||||
* @return The last modification time of the entry in local date-time
|
||||
*
|
||||
* @see #setTimeLocal(LocalDateTime)
|
||||
* @since 9
|
||||
*/
|
||||
public LocalDateTime getTimeLocal() {
|
||||
if (mtime != null) {
|
||||
return LocalDateTime.ofInstant(mtime.toInstant(), ZoneId.systemDefault());
|
||||
}
|
||||
int ms = (int)(xdostime >> 32);
|
||||
return LocalDateTime.of((int)(((xdostime >> 25) & 0x7f) + 1980),
|
||||
(int)((xdostime >> 21) & 0x0f),
|
||||
(int)((xdostime >> 16) & 0x1f),
|
||||
(int)((xdostime >> 11) & 0x1f),
|
||||
(int)((xdostime >> 5) & 0x3f),
|
||||
(int)((xdostime << 1) & 0x3e) + ms / 1000,
|
||||
(ms % 1000) * 1000_000);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the last modification time of the entry.
|
||||
*
|
||||
* <p> When output to a ZIP file or ZIP file formatted output stream
|
||||
* the last modification time set by this method will be stored into
|
||||
* zip file entry's {@code date and time fields} in {@code standard
|
||||
* MS-DOS date and time format}), and the extended timestamp fields
|
||||
* in {@code optional extra data} in UTC time.
|
||||
*
|
||||
* @param time
|
||||
* The last modification time of the entry
|
||||
* @return This zip entry
|
||||
*
|
||||
* @throws NullPointerException if the {@code time} is null
|
||||
*
|
||||
* @see #getLastModifiedTime()
|
||||
* @since 1.8
|
||||
*/
|
||||
public ZipEntry setLastModifiedTime(FileTime time) {
|
||||
this.mtime = Objects.requireNonNull(time, "lastModifiedTime");
|
||||
this.xdostime = javaToExtendedDosTime(time.to(TimeUnit.MILLISECONDS));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification time of the entry.
|
||||
*
|
||||
* <p> If the entry is read from a ZIP file or ZIP file formatted
|
||||
* input stream, this is the last modification time from the zip
|
||||
* file entry's {@code optional extra data} if the extended timestamp
|
||||
* fields are present. Otherwise the last modification time is read
|
||||
* from the entry's {@code date and time fields}, the {@link
|
||||
* java.util.TimeZone#getDefault() default TimeZone} is used to convert
|
||||
* the standard MS-DOS formatted date and time to the epoch time.
|
||||
*
|
||||
* @return The last modification time of the entry, null if not specified
|
||||
*
|
||||
* @see #setLastModifiedTime(FileTime)
|
||||
* @since 1.8
|
||||
*/
|
||||
public FileTime getLastModifiedTime() {
|
||||
if (mtime != null)
|
||||
return mtime;
|
||||
if (xdostime == -1)
|
||||
return null;
|
||||
return FileTime.from(getTime(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last access time of the entry.
|
||||
*
|
||||
* <p> If set, the last access time will be stored into the extended
|
||||
* timestamp fields of entry's {@code optional extra data}, when output
|
||||
* to a ZIP file or ZIP file formatted stream.
|
||||
*
|
||||
* @param time
|
||||
* The last access time of the entry
|
||||
* @return This zip entry
|
||||
*
|
||||
* @throws NullPointerException if the {@code time} is null
|
||||
*
|
||||
* @see #getLastAccessTime()
|
||||
* @since 1.8
|
||||
*/
|
||||
public ZipEntry setLastAccessTime(FileTime time) {
|
||||
this.atime = Objects.requireNonNull(time, "lastAccessTime");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last access time of the entry.
|
||||
*
|
||||
* <p> The last access time is from the extended timestamp fields
|
||||
* of entry's {@code optional extra data} when read from a ZIP file
|
||||
* or ZIP file formatted stream.
|
||||
*
|
||||
* @return The last access time of the entry, null if not specified
|
||||
|
||||
* @see #setLastAccessTime(FileTime)
|
||||
* @since 1.8
|
||||
*/
|
||||
public FileTime getLastAccessTime() {
|
||||
return atime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creation time of the entry.
|
||||
*
|
||||
* <p> If set, the creation time will be stored into the extended
|
||||
* timestamp fields of entry's {@code optional extra data}, when
|
||||
* output to a ZIP file or ZIP file formatted stream.
|
||||
*
|
||||
* @param time
|
||||
* The creation time of the entry
|
||||
* @return This zip entry
|
||||
*
|
||||
* @throws NullPointerException if the {@code time} is null
|
||||
*
|
||||
* @see #getCreationTime()
|
||||
* @since 1.8
|
||||
*/
|
||||
public ZipEntry setCreationTime(FileTime time) {
|
||||
this.ctime = Objects.requireNonNull(time, "creationTime");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation time of the entry.
|
||||
*
|
||||
* <p> The creation time is from the extended timestamp fields of
|
||||
* entry's {@code optional extra data} when read from a ZIP file
|
||||
* or ZIP file formatted stream.
|
||||
*
|
||||
* @return the creation time of the entry, null if not specified
|
||||
* @see #setCreationTime(FileTime)
|
||||
* @since 1.8
|
||||
*/
|
||||
public FileTime getCreationTime() {
|
||||
return ctime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uncompressed size of the entry data.
|
||||
*
|
||||
* @param size the uncompressed size in bytes
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified size is less
|
||||
* than 0, is greater than 0xFFFFFFFF when
|
||||
* <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
|
||||
* or is less than 0 when ZIP64 is supported
|
||||
* @see #getSize()
|
||||
*/
|
||||
public void setSize(long size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("invalid entry size");
|
||||
}
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uncompressed size of the entry data.
|
||||
*
|
||||
* @return the uncompressed size of the entry data, or -1 if not known
|
||||
* @see #setSize(long)
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the compressed entry data.
|
||||
*
|
||||
* <p> In the case of a stored entry, the compressed size will be the same
|
||||
* as the uncompressed size of the entry.
|
||||
*
|
||||
* @return the size of the compressed entry data, or -1 if not known
|
||||
* @see #setCompressedSize(long)
|
||||
*/
|
||||
public long getCompressedSize() {
|
||||
return csize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of the compressed entry data.
|
||||
*
|
||||
* @param csize the compressed size to set
|
||||
*
|
||||
* @see #getCompressedSize()
|
||||
*/
|
||||
public void setCompressedSize(long csize) {
|
||||
this.csize = csize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CRC-32 checksum of the uncompressed entry data.
|
||||
*
|
||||
* @param crc the CRC-32 value
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified CRC-32 value is
|
||||
* less than 0 or greater than 0xFFFFFFFF
|
||||
* @see #getCrc()
|
||||
*/
|
||||
public void setCrc(long crc) {
|
||||
if (crc < 0 || crc > 0xFFFFFFFFL) {
|
||||
throw new IllegalArgumentException("invalid entry crc-32");
|
||||
}
|
||||
this.crc = crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CRC-32 checksum of the uncompressed entry data.
|
||||
*
|
||||
* @return the CRC-32 checksum of the uncompressed entry data, or -1 if
|
||||
* not known
|
||||
*
|
||||
* @see #setCrc(long)
|
||||
*/
|
||||
public long getCrc() {
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the compression method for the entry.
|
||||
*
|
||||
* @param method the compression method, either STORED or DEFLATED
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified compression
|
||||
* method is invalid
|
||||
* @see #getMethod()
|
||||
*/
|
||||
public void setMethod(int method) {
|
||||
if (method != STORED && method != DEFLATED) {
|
||||
throw new IllegalArgumentException("invalid compression method");
|
||||
}
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compression method of the entry.
|
||||
*
|
||||
* @return the compression method of the entry, or -1 if not specified
|
||||
* @see #setMethod(int)
|
||||
*/
|
||||
public int getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional extra field data for the entry.
|
||||
*
|
||||
* <p> Invoking this method may change this entry's last modification
|
||||
* time, last access time and creation time, if the {@code extra} field
|
||||
* data includes the extensible timestamp fields, such as {@code NTFS tag
|
||||
* 0x0001} or {@code Info-ZIP Extended Timestamp}, as specified in
|
||||
* <a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">Info-ZIP
|
||||
* Application Note 970311</a>.
|
||||
*
|
||||
* @param extra
|
||||
* The extra field data bytes
|
||||
*
|
||||
* @throws IllegalArgumentException if the length of the specified
|
||||
* extra field data is greater than 0xFFFF bytes
|
||||
*
|
||||
* @see #getExtra()
|
||||
*/
|
||||
public void setExtra(byte[] extra) {
|
||||
setExtra0(extra, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional extra field data for the entry.
|
||||
*
|
||||
* @param extra
|
||||
* the extra field data bytes
|
||||
* @param doZIP64
|
||||
* if true, set size and csize from ZIP64 fields if present
|
||||
*/
|
||||
void setExtra0(byte[] extra, boolean doZIP64) {
|
||||
if (extra != null) {
|
||||
if (extra.length > 0xFFFF) {
|
||||
throw new IllegalArgumentException("invalid extra field length");
|
||||
}
|
||||
// extra fields are in "HeaderID(2)DataSize(2)Data... format
|
||||
int off = 0;
|
||||
int len = extra.length;
|
||||
while (off + 4 < len) {
|
||||
int tag = get16(extra, off);
|
||||
int sz = get16(extra, off + 2);
|
||||
off += 4;
|
||||
if (off + sz > len) // invalid data
|
||||
break;
|
||||
switch (tag) {
|
||||
case EXTID_ZIP64:
|
||||
if (doZIP64) {
|
||||
// LOC extra zip64 entry MUST include BOTH original
|
||||
// and compressed file size fields.
|
||||
// If invalid zip64 extra fields, simply skip. Even
|
||||
// it's rare, it's possible the entry size happens to
|
||||
// be the magic value and it "accidently" has some
|
||||
// bytes in extra match the id.
|
||||
if (sz >= 16) {
|
||||
size = get64(extra, off);
|
||||
csize = get64(extra, off + 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXTID_NTFS:
|
||||
if (sz < 32) // reserved 4 bytes + tag 2 bytes + size 2 bytes
|
||||
break; // m[a|c]time 24 bytes
|
||||
int pos = off + 4; // reserved 4 bytes
|
||||
if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24)
|
||||
break;
|
||||
long wtime = get64(extra, pos + 4);
|
||||
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
|
||||
mtime = winTimeToFileTime(wtime);
|
||||
}
|
||||
wtime = get64(extra, pos + 12);
|
||||
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
|
||||
atime = winTimeToFileTime(wtime);
|
||||
}
|
||||
wtime = get64(extra, pos + 20);
|
||||
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
|
||||
ctime = winTimeToFileTime(wtime);
|
||||
}
|
||||
break;
|
||||
case EXTID_EXTT:
|
||||
int flag = Byte.toUnsignedInt(extra[off]);
|
||||
int sz0 = 1;
|
||||
// The CEN-header extra field contains the modification
|
||||
// time only, or no timestamp at all. 'sz' is used to
|
||||
// flag its presence or absence. But if mtime is present
|
||||
// in LOC it must be present in CEN as well.
|
||||
if ((flag & 0x1) != 0 && (sz0 + 4) <= sz) {
|
||||
mtime = unixTimeToFileTime(get32S(extra, off + sz0));
|
||||
sz0 += 4;
|
||||
}
|
||||
if ((flag & 0x2) != 0 && (sz0 + 4) <= sz) {
|
||||
atime = unixTimeToFileTime(get32S(extra, off + sz0));
|
||||
sz0 += 4;
|
||||
}
|
||||
if ((flag & 0x4) != 0 && (sz0 + 4) <= sz) {
|
||||
ctime = unixTimeToFileTime(get32S(extra, off + sz0));
|
||||
sz0 += 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
off += sz;
|
||||
}
|
||||
}
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra field data for the entry.
|
||||
*
|
||||
* @return the extra field data for the entry, or null if none
|
||||
*
|
||||
* @see #setExtra(byte[])
|
||||
*/
|
||||
public byte[] getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional comment string for the entry.
|
||||
*
|
||||
* <p>ZIP entry comments have maximum length of 0xffff. If the length of the
|
||||
* specified comment string is greater than 0xFFFF bytes after encoding, only
|
||||
* the first 0xFFFF bytes are output to the ZIP file entry.
|
||||
*
|
||||
* @param comment the comment string
|
||||
*
|
||||
* @see #getComment()
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the comment string for the entry.
|
||||
*
|
||||
* @return the comment string for the entry, or null if none
|
||||
*
|
||||
* @see #setComment(String)
|
||||
*/
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a directory entry. A directory entry is
|
||||
* defined to be one whose name ends with a '/'.
|
||||
* @return true if this is a directory entry
|
||||
*/
|
||||
public boolean isDirectory() {
|
||||
return name.endsWith("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the ZIP entry.
|
||||
*/
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code value for this entry.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this entry.
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
ZipEntry e = (ZipEntry)super.clone();
|
||||
e.extra = (extra == null) ? null : extra.clone();
|
||||
return e;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// This should never happen, since we are Cloneable
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
}
|
44
src/java.base/share/classes/java/util/zip/ZipError.java
Normal file
44
src/java.base/share/classes/java/util/zip/ZipError.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
/**
|
||||
* Signals that an unrecoverable error has occurred.
|
||||
*
|
||||
* @author Dave Bristor
|
||||
* @since 1.6
|
||||
*/
|
||||
public class ZipError extends InternalError {
|
||||
private static final long serialVersionUID = 853973422266861979L;
|
||||
|
||||
/**
|
||||
* Constructs a ZipError with the given detail message.
|
||||
* @param s the {@code String} containing a detail message
|
||||
*/
|
||||
public ZipError(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
60
src/java.base/share/classes/java/util/zip/ZipException.java
Normal file
60
src/java.base/share/classes/java/util/zip/ZipException.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Signals that a Zip exception of some sort has occurred.
|
||||
*
|
||||
* @author unascribed
|
||||
* @see java.io.IOException
|
||||
* @since 1.1
|
||||
*/
|
||||
|
||||
public
|
||||
class ZipException extends IOException {
|
||||
private static final long serialVersionUID = 8000196834066748623L;
|
||||
|
||||
/**
|
||||
* Constructs a <code>ZipException</code> with <code>null</code>
|
||||
* as its error detail message.
|
||||
*/
|
||||
public ZipException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>ZipException</code> with the specified detail
|
||||
* message.
|
||||
*
|
||||
* @param s the detail message.
|
||||
*/
|
||||
|
||||
public ZipException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
1345
src/java.base/share/classes/java/util/zip/ZipFile.java
Normal file
1345
src/java.base/share/classes/java/util/zip/ZipFile.java
Normal file
File diff suppressed because it is too large
Load diff
426
src/java.base/share/classes/java/util/zip/ZipInputStream.java
Normal file
426
src/java.base/share/classes/java/util/zip/ZipInputStream.java
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import static java.util.zip.ZipConstants64.*;
|
||||
import static java.util.zip.ZipUtils.*;
|
||||
|
||||
/**
|
||||
* This class implements an input stream filter for reading files in the
|
||||
* ZIP file format. Includes support for both compressed and uncompressed
|
||||
* entries.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class ZipInputStream extends InflaterInputStream implements ZipConstants {
|
||||
private ZipEntry entry;
|
||||
private int flag;
|
||||
private CRC32 crc = new CRC32();
|
||||
private long remaining;
|
||||
private byte[] tmpbuf = new byte[512];
|
||||
|
||||
private static final int STORED = ZipEntry.STORED;
|
||||
private static final int DEFLATED = ZipEntry.DEFLATED;
|
||||
|
||||
private boolean closed = false;
|
||||
// this flag is set to true after EOF has reached for
|
||||
// one entry
|
||||
private boolean entryEOF = false;
|
||||
|
||||
private ZipCoder zc;
|
||||
|
||||
/**
|
||||
* Check to make sure that this stream has not been closed
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ZIP input stream.
|
||||
*
|
||||
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
|
||||
* decode the entry names.
|
||||
*
|
||||
* @param in the actual input stream
|
||||
*/
|
||||
public ZipInputStream(InputStream in) {
|
||||
this(in, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ZIP input stream.
|
||||
*
|
||||
* @param in the actual input stream
|
||||
*
|
||||
* @param charset
|
||||
* The {@linkplain java.nio.charset.Charset charset} to be
|
||||
* used to decode the ZIP entry name (ignored if the
|
||||
* <a href="package-summary.html#lang_encoding"> language
|
||||
* encoding bit</a> of the ZIP entry's general purpose bit
|
||||
* flag is set).
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public ZipInputStream(InputStream in, Charset charset) {
|
||||
super(new PushbackInputStream(in, 512), new Inflater(true), 512);
|
||||
usesDefaultInflater = true;
|
||||
if(in == null) {
|
||||
throw new NullPointerException("in is null");
|
||||
}
|
||||
if (charset == null)
|
||||
throw new NullPointerException("charset is null");
|
||||
this.zc = ZipCoder.get(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next ZIP file entry and positions the stream at the
|
||||
* beginning of the entry data.
|
||||
* @return the next ZIP file entry, or null if there are no more entries
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public ZipEntry getNextEntry() throws IOException {
|
||||
ensureOpen();
|
||||
if (entry != null) {
|
||||
closeEntry();
|
||||
}
|
||||
crc.reset();
|
||||
inf.reset();
|
||||
if ((entry = readLOC()) == null) {
|
||||
return null;
|
||||
}
|
||||
if (entry.method == STORED) {
|
||||
remaining = entry.size;
|
||||
}
|
||||
entryEOF = false;
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current ZIP entry and positions the stream for reading the
|
||||
* next entry.
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void closeEntry() throws IOException {
|
||||
ensureOpen();
|
||||
while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
|
||||
entryEOF = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 after EOF has reached for the current entry data,
|
||||
* otherwise always return 1.
|
||||
* <p>
|
||||
* Programs should not count on this method to return the actual number
|
||||
* of bytes that could be read without blocking.
|
||||
*
|
||||
* @return 1 before EOF and 0 after EOF has reached for current entry.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
ensureOpen();
|
||||
if (entryEOF) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the current ZIP entry into an array of bytes.
|
||||
* If <code>len</code> is not zero, the method
|
||||
* blocks until some input is available; otherwise, no
|
||||
* bytes are read and <code>0</code> is returned.
|
||||
* @param b the buffer into which the data is read
|
||||
* @param off the start offset in the destination array <code>b</code>
|
||||
* @param len the maximum number of bytes read
|
||||
* @return the actual number of bytes read, or -1 if the end of the
|
||||
* entry is reached
|
||||
* @exception NullPointerException if <code>b</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is negative,
|
||||
* <code>len</code> is negative, or <code>len</code> is greater than
|
||||
* <code>b.length - off</code>
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (entry == null) {
|
||||
return -1;
|
||||
}
|
||||
switch (entry.method) {
|
||||
case DEFLATED:
|
||||
len = super.read(b, off, len);
|
||||
if (len == -1) {
|
||||
readEnd(entry);
|
||||
entryEOF = true;
|
||||
entry = null;
|
||||
} else {
|
||||
crc.update(b, off, len);
|
||||
}
|
||||
return len;
|
||||
case STORED:
|
||||
if (remaining <= 0) {
|
||||
entryEOF = true;
|
||||
entry = null;
|
||||
return -1;
|
||||
}
|
||||
if (len > remaining) {
|
||||
len = (int)remaining;
|
||||
}
|
||||
len = in.read(b, off, len);
|
||||
if (len == -1) {
|
||||
throw new ZipException("unexpected EOF");
|
||||
}
|
||||
crc.update(b, off, len);
|
||||
remaining -= len;
|
||||
if (remaining == 0 && entry.crc != crc.getValue()) {
|
||||
throw new ZipException(
|
||||
"invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
|
||||
" but got 0x" + Long.toHexString(crc.getValue()) + ")");
|
||||
}
|
||||
return len;
|
||||
default:
|
||||
throw new ZipException("invalid compression method");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips specified number of bytes in the current ZIP entry.
|
||||
* @param n the number of bytes to skip
|
||||
* @return the actual number of bytes skipped
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
* @exception IllegalArgumentException if {@code n < 0}
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("negative skip length");
|
||||
}
|
||||
ensureOpen();
|
||||
int max = (int)Math.min(n, Integer.MAX_VALUE);
|
||||
int total = 0;
|
||||
while (total < max) {
|
||||
int len = max - total;
|
||||
if (len > tmpbuf.length) {
|
||||
len = tmpbuf.length;
|
||||
}
|
||||
len = read(tmpbuf, 0, len);
|
||||
if (len == -1) {
|
||||
entryEOF = true;
|
||||
break;
|
||||
}
|
||||
total += len;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources associated
|
||||
* with the stream.
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed) {
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] b = new byte[256];
|
||||
|
||||
/*
|
||||
* Reads local file (LOC) header for next entry.
|
||||
*/
|
||||
private ZipEntry readLOC() throws IOException {
|
||||
try {
|
||||
readFully(tmpbuf, 0, LOCHDR);
|
||||
} catch (EOFException e) {
|
||||
return null;
|
||||
}
|
||||
if (get32(tmpbuf, 0) != LOCSIG) {
|
||||
return null;
|
||||
}
|
||||
// get flag first, we need check EFS.
|
||||
flag = get16(tmpbuf, LOCFLG);
|
||||
// get the entry name and create the ZipEntry first
|
||||
int len = get16(tmpbuf, LOCNAM);
|
||||
int blen = b.length;
|
||||
if (len > blen) {
|
||||
do {
|
||||
blen = blen * 2;
|
||||
} while (len > blen);
|
||||
b = new byte[blen];
|
||||
}
|
||||
readFully(b, 0, len);
|
||||
// Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
|
||||
ZipEntry e = createZipEntry(((flag & EFS) != 0)
|
||||
? zc.toStringUTF8(b, len)
|
||||
: zc.toString(b, len));
|
||||
// now get the remaining fields for the entry
|
||||
if ((flag & 1) == 1) {
|
||||
throw new ZipException("encrypted ZIP entry not supported");
|
||||
}
|
||||
e.method = get16(tmpbuf, LOCHOW);
|
||||
e.xdostime = get32(tmpbuf, LOCTIM);
|
||||
if ((flag & 8) == 8) {
|
||||
/* "Data Descriptor" present */
|
||||
if (e.method != DEFLATED) {
|
||||
throw new ZipException(
|
||||
"only DEFLATED entries can have EXT descriptor");
|
||||
}
|
||||
} else {
|
||||
e.crc = get32(tmpbuf, LOCCRC);
|
||||
e.csize = get32(tmpbuf, LOCSIZ);
|
||||
e.size = get32(tmpbuf, LOCLEN);
|
||||
}
|
||||
len = get16(tmpbuf, LOCEXT);
|
||||
if (len > 0) {
|
||||
byte[] extra = new byte[len];
|
||||
readFully(extra, 0, len);
|
||||
e.setExtra0(extra,
|
||||
e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ZipEntry</code> object for the specified
|
||||
* entry name.
|
||||
*
|
||||
* @param name the ZIP file entry name
|
||||
* @return the ZipEntry just created
|
||||
*/
|
||||
protected ZipEntry createZipEntry(String name) {
|
||||
return new ZipEntry(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads end of deflated entry as well as EXT descriptor if present.
|
||||
*
|
||||
* Local headers for DEFLATED entries may optionally be followed by a
|
||||
* data descriptor, and that data descriptor may optionally contain a
|
||||
* leading signature (EXTSIG).
|
||||
*
|
||||
* From the zip spec http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
*
|
||||
* """Although not originally assigned a signature, the value 0x08074b50
|
||||
* has commonly been adopted as a signature value for the data descriptor
|
||||
* record. Implementers should be aware that ZIP files may be
|
||||
* encountered with or without this signature marking data descriptors
|
||||
* and should account for either case when reading ZIP files to ensure
|
||||
* compatibility."""
|
||||
*/
|
||||
private void readEnd(ZipEntry e) throws IOException {
|
||||
int n = inf.getRemaining();
|
||||
if (n > 0) {
|
||||
((PushbackInputStream)in).unread(buf, len - n, n);
|
||||
}
|
||||
if ((flag & 8) == 8) {
|
||||
/* "Data Descriptor" present */
|
||||
if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
|
||||
inf.getBytesRead() > ZIP64_MAGICVAL) {
|
||||
// ZIP64 format
|
||||
readFully(tmpbuf, 0, ZIP64_EXTHDR);
|
||||
long sig = get32(tmpbuf, 0);
|
||||
if (sig != EXTSIG) { // no EXTSIG present
|
||||
e.crc = sig;
|
||||
e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
|
||||
e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
|
||||
((PushbackInputStream)in).unread(
|
||||
tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC);
|
||||
} else {
|
||||
e.crc = get32(tmpbuf, ZIP64_EXTCRC);
|
||||
e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
|
||||
e.size = get64(tmpbuf, ZIP64_EXTLEN);
|
||||
}
|
||||
} else {
|
||||
readFully(tmpbuf, 0, EXTHDR);
|
||||
long sig = get32(tmpbuf, 0);
|
||||
if (sig != EXTSIG) { // no EXTSIG present
|
||||
e.crc = sig;
|
||||
e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
|
||||
e.size = get32(tmpbuf, EXTLEN - EXTCRC);
|
||||
((PushbackInputStream)in).unread(
|
||||
tmpbuf, EXTHDR - EXTCRC, EXTCRC);
|
||||
} else {
|
||||
e.crc = get32(tmpbuf, EXTCRC);
|
||||
e.csize = get32(tmpbuf, EXTSIZ);
|
||||
e.size = get32(tmpbuf, EXTLEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e.size != inf.getBytesWritten()) {
|
||||
throw new ZipException(
|
||||
"invalid entry size (expected " + e.size +
|
||||
" but got " + inf.getBytesWritten() + " bytes)");
|
||||
}
|
||||
if (e.csize != inf.getBytesRead()) {
|
||||
throw new ZipException(
|
||||
"invalid entry compressed size (expected " + e.csize +
|
||||
" but got " + inf.getBytesRead() + " bytes)");
|
||||
}
|
||||
if (e.crc != crc.getValue()) {
|
||||
throw new ZipException(
|
||||
"invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
|
||||
" but got 0x" + Long.toHexString(crc.getValue()) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads bytes, blocking until all bytes are read.
|
||||
*/
|
||||
private void readFully(byte[] b, int off, int len) throws IOException {
|
||||
while (len > 0) {
|
||||
int n = in.read(b, off, len);
|
||||
if (n == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
off += n;
|
||||
len -= n;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
808
src/java.base/share/classes/java/util/zip/ZipOutputStream.java
Normal file
808
src/java.base/share/classes/java/util/zip/ZipOutputStream.java
Normal file
|
@ -0,0 +1,808 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Vector;
|
||||
import java.util.HashSet;
|
||||
import static java.util.zip.ZipConstants64.*;
|
||||
import static java.util.zip.ZipUtils.*;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class implements an output stream filter for writing files in the
|
||||
* ZIP file format. Includes support for both compressed and uncompressed
|
||||
* entries.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
public
|
||||
class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
|
||||
|
||||
/**
|
||||
* Whether to use ZIP64 for zip files with more than 64k entries.
|
||||
* Until ZIP64 support in zip implementations is ubiquitous, this
|
||||
* system property allows the creation of zip files which can be
|
||||
* read by legacy zip implementations which tolerate "incorrect"
|
||||
* total entry count fields, such as the ones in jdk6, and even
|
||||
* some in jdk7.
|
||||
*/
|
||||
private static final boolean inhibitZip64 =
|
||||
Boolean.parseBoolean(
|
||||
GetPropertyAction.privilegedGetProperty("jdk.util.zip.inhibitZip64"));
|
||||
|
||||
private static class XEntry {
|
||||
final ZipEntry entry;
|
||||
final long offset;
|
||||
public XEntry(ZipEntry entry, long offset) {
|
||||
this.entry = entry;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
private XEntry current;
|
||||
private Vector<XEntry> xentries = new Vector<>();
|
||||
private HashSet<String> names = new HashSet<>();
|
||||
private CRC32 crc = new CRC32();
|
||||
private long written = 0;
|
||||
private long locoff = 0;
|
||||
private byte[] comment;
|
||||
private int method = DEFLATED;
|
||||
private boolean finished;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
private final ZipCoder zc;
|
||||
|
||||
private static int version(ZipEntry e) throws ZipException {
|
||||
switch (e.method) {
|
||||
case DEFLATED: return 20;
|
||||
case STORED: return 10;
|
||||
default: throw new ZipException("unsupported compression method");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to make sure that this stream has not been closed.
|
||||
*/
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Compression method for uncompressed (STORED) entries.
|
||||
*/
|
||||
public static final int STORED = ZipEntry.STORED;
|
||||
|
||||
/**
|
||||
* Compression method for compressed (DEFLATED) entries.
|
||||
*/
|
||||
public static final int DEFLATED = ZipEntry.DEFLATED;
|
||||
|
||||
/**
|
||||
* Creates a new ZIP output stream.
|
||||
*
|
||||
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
|
||||
* to encode the entry names and comments.
|
||||
*
|
||||
* @param out the actual output stream
|
||||
*/
|
||||
public ZipOutputStream(OutputStream out) {
|
||||
this(out, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ZIP output stream.
|
||||
*
|
||||
* @param out the actual output stream
|
||||
*
|
||||
* @param charset the {@linkplain java.nio.charset.Charset charset}
|
||||
* to be used to encode the entry names and comments
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public ZipOutputStream(OutputStream out, Charset charset) {
|
||||
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
|
||||
if (charset == null)
|
||||
throw new NullPointerException("charset is null");
|
||||
this.zc = ZipCoder.get(charset);
|
||||
usesDefaultDeflater = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ZIP file comment.
|
||||
* @param comment the comment string
|
||||
* @exception IllegalArgumentException if the length of the specified
|
||||
* ZIP file comment is greater than 0xFFFF bytes
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
if (comment != null) {
|
||||
this.comment = zc.getBytes(comment);
|
||||
if (this.comment.length > 0xffff)
|
||||
throw new IllegalArgumentException("ZIP file comment too long.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default compression method for subsequent entries. This
|
||||
* default will be used whenever the compression method is not specified
|
||||
* for an individual ZIP file entry, and is initially set to DEFLATED.
|
||||
* @param method the default compression method
|
||||
* @exception IllegalArgumentException if the specified compression method
|
||||
* is invalid
|
||||
*/
|
||||
public void setMethod(int method) {
|
||||
if (method != DEFLATED && method != STORED) {
|
||||
throw new IllegalArgumentException("invalid compression method");
|
||||
}
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the compression level for subsequent entries which are DEFLATED.
|
||||
* The default setting is DEFAULT_COMPRESSION.
|
||||
* @param level the compression level (0-9)
|
||||
* @exception IllegalArgumentException if the compression level is invalid
|
||||
*/
|
||||
public void setLevel(int level) {
|
||||
def.setLevel(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins writing a new ZIP file entry and positions the stream to the
|
||||
* start of the entry data. Closes the current entry if still active.
|
||||
* The default compression method will be used if no compression method
|
||||
* was specified for the entry, and the current time will be used if
|
||||
* the entry has no set modification time.
|
||||
* @param e the ZIP entry to be written
|
||||
* @exception ZipException if a ZIP format error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void putNextEntry(ZipEntry e) throws IOException {
|
||||
ensureOpen();
|
||||
if (current != null) {
|
||||
closeEntry(); // close previous entry
|
||||
}
|
||||
if (e.xdostime == -1) {
|
||||
// by default, do NOT use extended timestamps in extra
|
||||
// data, for now.
|
||||
e.setTime(System.currentTimeMillis());
|
||||
}
|
||||
if (e.method == -1) {
|
||||
e.method = method; // use default method
|
||||
}
|
||||
// store size, compressed size, and crc-32 in LOC header
|
||||
e.flag = 0;
|
||||
switch (e.method) {
|
||||
case DEFLATED:
|
||||
// store size, compressed size, and crc-32 in data descriptor
|
||||
// immediately following the compressed entry data
|
||||
if (e.size == -1 || e.csize == -1 || e.crc == -1)
|
||||
e.flag = 8;
|
||||
|
||||
break;
|
||||
case STORED:
|
||||
// compressed size, uncompressed size, and crc-32 must all be
|
||||
// set for entries using STORED compression method
|
||||
if (e.size == -1) {
|
||||
e.size = e.csize;
|
||||
} else if (e.csize == -1) {
|
||||
e.csize = e.size;
|
||||
} else if (e.size != e.csize) {
|
||||
throw new ZipException(
|
||||
"STORED entry where compressed != uncompressed size");
|
||||
}
|
||||
if (e.size == -1 || e.crc == -1) {
|
||||
throw new ZipException(
|
||||
"STORED entry missing size, compressed size, or crc-32");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ZipException("unsupported compression method");
|
||||
}
|
||||
if (! names.add(e.name)) {
|
||||
throw new ZipException("duplicate entry: " + e.name);
|
||||
}
|
||||
if (zc.isUTF8())
|
||||
e.flag |= EFS;
|
||||
current = new XEntry(e, written);
|
||||
xentries.add(current);
|
||||
writeLOC(current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current ZIP entry and positions the stream for writing
|
||||
* the next entry.
|
||||
* @exception ZipException if a ZIP format error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void closeEntry() throws IOException {
|
||||
ensureOpen();
|
||||
if (current != null) {
|
||||
ZipEntry e = current.entry;
|
||||
switch (e.method) {
|
||||
case DEFLATED:
|
||||
def.finish();
|
||||
while (!def.finished()) {
|
||||
deflate();
|
||||
}
|
||||
if ((e.flag & 8) == 0) {
|
||||
// verify size, compressed size, and crc-32 settings
|
||||
if (e.size != def.getBytesRead()) {
|
||||
throw new ZipException(
|
||||
"invalid entry size (expected " + e.size +
|
||||
" but got " + def.getBytesRead() + " bytes)");
|
||||
}
|
||||
if (e.csize != def.getBytesWritten()) {
|
||||
throw new ZipException(
|
||||
"invalid entry compressed size (expected " +
|
||||
e.csize + " but got " + def.getBytesWritten() + " bytes)");
|
||||
}
|
||||
if (e.crc != crc.getValue()) {
|
||||
throw new ZipException(
|
||||
"invalid entry CRC-32 (expected 0x" +
|
||||
Long.toHexString(e.crc) + " but got 0x" +
|
||||
Long.toHexString(crc.getValue()) + ")");
|
||||
}
|
||||
} else {
|
||||
e.size = def.getBytesRead();
|
||||
e.csize = def.getBytesWritten();
|
||||
e.crc = crc.getValue();
|
||||
writeEXT(e);
|
||||
}
|
||||
def.reset();
|
||||
written += e.csize;
|
||||
break;
|
||||
case STORED:
|
||||
// we already know that both e.size and e.csize are the same
|
||||
if (e.size != written - locoff) {
|
||||
throw new ZipException(
|
||||
"invalid entry size (expected " + e.size +
|
||||
" but got " + (written - locoff) + " bytes)");
|
||||
}
|
||||
if (e.crc != crc.getValue()) {
|
||||
throw new ZipException(
|
||||
"invalid entry crc-32 (expected 0x" +
|
||||
Long.toHexString(e.crc) + " but got 0x" +
|
||||
Long.toHexString(crc.getValue()) + ")");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ZipException("invalid compression method");
|
||||
}
|
||||
crc.reset();
|
||||
current = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes to the current ZIP entry data. This method
|
||||
* will block until all the bytes are written.
|
||||
* @param b the data to be written
|
||||
* @param off the start offset in the data
|
||||
* @param len the number of bytes that are written
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public synchronized void write(byte[] b, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
ensureOpen();
|
||||
if (off < 0 || len < 0 || off > b.length - len) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (current == null) {
|
||||
throw new ZipException("no current ZIP entry");
|
||||
}
|
||||
ZipEntry entry = current.entry;
|
||||
switch (entry.method) {
|
||||
case DEFLATED:
|
||||
super.write(b, off, len);
|
||||
break;
|
||||
case STORED:
|
||||
written += len;
|
||||
if (written - locoff > entry.size) {
|
||||
throw new ZipException(
|
||||
"attempt to write past end of STORED entry");
|
||||
}
|
||||
out.write(b, off, len);
|
||||
break;
|
||||
default:
|
||||
throw new ZipException("invalid compression method");
|
||||
}
|
||||
crc.update(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes writing the contents of the ZIP output stream without closing
|
||||
* the underlying stream. Use this method when applying multiple filters
|
||||
* in succession to the same output stream.
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O exception has occurred
|
||||
*/
|
||||
public void finish() throws IOException {
|
||||
ensureOpen();
|
||||
if (finished) {
|
||||
return;
|
||||
}
|
||||
if (current != null) {
|
||||
closeEntry();
|
||||
}
|
||||
// write central directory
|
||||
long off = written;
|
||||
for (XEntry xentry : xentries)
|
||||
writeCEN(xentry);
|
||||
writeEND(off, written - off);
|
||||
finished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the ZIP output stream as well as the stream being filtered.
|
||||
* @exception ZipException if a ZIP file error has occurred
|
||||
* @exception IOException if an I/O error has occurred
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (!closed) {
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes local file (LOC) header for specified entry.
|
||||
*/
|
||||
private void writeLOC(XEntry xentry) throws IOException {
|
||||
ZipEntry e = xentry.entry;
|
||||
int flag = e.flag;
|
||||
boolean hasZip64 = false;
|
||||
int elen = getExtraLen(e.extra);
|
||||
|
||||
writeInt(LOCSIG); // LOC header signature
|
||||
if ((flag & 8) == 8) {
|
||||
writeShort(version(e)); // version needed to extract
|
||||
writeShort(flag); // general purpose bit flag
|
||||
writeShort(e.method); // compression method
|
||||
writeInt(e.xdostime); // last modification time
|
||||
// store size, uncompressed size, and crc-32 in data descriptor
|
||||
// immediately following compressed entry data
|
||||
writeInt(0);
|
||||
writeInt(0);
|
||||
writeInt(0);
|
||||
} else {
|
||||
if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
|
||||
hasZip64 = true;
|
||||
writeShort(45); // ver 4.5 for zip64
|
||||
} else {
|
||||
writeShort(version(e)); // version needed to extract
|
||||
}
|
||||
writeShort(flag); // general purpose bit flag
|
||||
writeShort(e.method); // compression method
|
||||
writeInt(e.xdostime); // last modification time
|
||||
writeInt(e.crc); // crc-32
|
||||
if (hasZip64) {
|
||||
writeInt(ZIP64_MAGICVAL);
|
||||
writeInt(ZIP64_MAGICVAL);
|
||||
elen += 20; //headid(2) + size(2) + size(8) + csize(8)
|
||||
} else {
|
||||
writeInt(e.csize); // compressed size
|
||||
writeInt(e.size); // uncompressed size
|
||||
}
|
||||
}
|
||||
byte[] nameBytes = zc.getBytes(e.name);
|
||||
writeShort(nameBytes.length);
|
||||
|
||||
int elenEXTT = 0; // info-zip extended timestamp
|
||||
int flagEXTT = 0;
|
||||
long umtime = -1;
|
||||
long uatime = -1;
|
||||
long uctime = -1;
|
||||
if (e.mtime != null) {
|
||||
elenEXTT += 4;
|
||||
flagEXTT |= EXTT_FLAG_LMT;
|
||||
umtime = fileTimeToUnixTime(e.mtime);
|
||||
}
|
||||
if (e.atime != null) {
|
||||
elenEXTT += 4;
|
||||
flagEXTT |= EXTT_FLAG_LAT;
|
||||
uatime = fileTimeToUnixTime(e.atime);
|
||||
}
|
||||
if (e.ctime != null) {
|
||||
elenEXTT += 4;
|
||||
flagEXTT |= EXTT_FLAT_CT;
|
||||
uctime = fileTimeToUnixTime(e.ctime);
|
||||
}
|
||||
if (flagEXTT != 0) {
|
||||
// to use ntfs time if any m/a/ctime is beyond unixtime upper bound
|
||||
if (umtime > UPPER_UNIXTIME_BOUND ||
|
||||
uatime > UPPER_UNIXTIME_BOUND ||
|
||||
uctime > UPPER_UNIXTIME_BOUND) {
|
||||
elen += 36; // NTFS time, total 36 bytes
|
||||
} else {
|
||||
elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
|
||||
}
|
||||
}
|
||||
writeShort(elen);
|
||||
writeBytes(nameBytes, 0, nameBytes.length);
|
||||
if (hasZip64) {
|
||||
writeShort(ZIP64_EXTID);
|
||||
writeShort(16);
|
||||
writeLong(e.size);
|
||||
writeLong(e.csize);
|
||||
}
|
||||
if (flagEXTT != 0) {
|
||||
if (umtime > UPPER_UNIXTIME_BOUND ||
|
||||
uatime > UPPER_UNIXTIME_BOUND ||
|
||||
uctime > UPPER_UNIXTIME_BOUND) {
|
||||
writeShort(EXTID_NTFS); // id
|
||||
writeShort(32); // data size
|
||||
writeInt(0); // reserved
|
||||
writeShort(0x0001); // NTFS attr tag
|
||||
writeShort(24);
|
||||
writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
|
||||
: fileTimeToWinTime(e.mtime));
|
||||
writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
|
||||
: fileTimeToWinTime(e.atime));
|
||||
writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
|
||||
: fileTimeToWinTime(e.ctime));
|
||||
} else {
|
||||
writeShort(EXTID_EXTT);
|
||||
writeShort(elenEXTT + 1); // flag + data
|
||||
writeByte(flagEXTT);
|
||||
if (e.mtime != null)
|
||||
writeInt(umtime);
|
||||
if (e.atime != null)
|
||||
writeInt(uatime);
|
||||
if (e.ctime != null)
|
||||
writeInt(uctime);
|
||||
}
|
||||
}
|
||||
writeExtra(e.extra);
|
||||
locoff = written;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes extra data descriptor (EXT) for specified entry.
|
||||
*/
|
||||
private void writeEXT(ZipEntry e) throws IOException {
|
||||
writeInt(EXTSIG); // EXT header signature
|
||||
writeInt(e.crc); // crc-32
|
||||
if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
|
||||
writeLong(e.csize);
|
||||
writeLong(e.size);
|
||||
} else {
|
||||
writeInt(e.csize); // compressed size
|
||||
writeInt(e.size); // uncompressed size
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write central directory (CEN) header for specified entry.
|
||||
* REMIND: add support for file attributes
|
||||
*/
|
||||
private void writeCEN(XEntry xentry) throws IOException {
|
||||
ZipEntry e = xentry.entry;
|
||||
int flag = e.flag;
|
||||
int version = version(e);
|
||||
long csize = e.csize;
|
||||
long size = e.size;
|
||||
long offset = xentry.offset;
|
||||
int elenZIP64 = 0;
|
||||
boolean hasZip64 = false;
|
||||
|
||||
if (e.csize >= ZIP64_MAGICVAL) {
|
||||
csize = ZIP64_MAGICVAL;
|
||||
elenZIP64 += 8; // csize(8)
|
||||
hasZip64 = true;
|
||||
}
|
||||
if (e.size >= ZIP64_MAGICVAL) {
|
||||
size = ZIP64_MAGICVAL; // size(8)
|
||||
elenZIP64 += 8;
|
||||
hasZip64 = true;
|
||||
}
|
||||
if (xentry.offset >= ZIP64_MAGICVAL) {
|
||||
offset = ZIP64_MAGICVAL;
|
||||
elenZIP64 += 8; // offset(8)
|
||||
hasZip64 = true;
|
||||
}
|
||||
writeInt(CENSIG); // CEN header signature
|
||||
if (hasZip64) {
|
||||
writeShort(45); // ver 4.5 for zip64
|
||||
writeShort(45);
|
||||
} else {
|
||||
writeShort(version); // version made by
|
||||
writeShort(version); // version needed to extract
|
||||
}
|
||||
writeShort(flag); // general purpose bit flag
|
||||
writeShort(e.method); // compression method
|
||||
writeInt(e.xdostime); // last modification time
|
||||
writeInt(e.crc); // crc-32
|
||||
writeInt(csize); // compressed size
|
||||
writeInt(size); // uncompressed size
|
||||
byte[] nameBytes = zc.getBytes(e.name);
|
||||
writeShort(nameBytes.length);
|
||||
|
||||
int elen = getExtraLen(e.extra);
|
||||
if (hasZip64) {
|
||||
elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
|
||||
}
|
||||
// cen info-zip extended timestamp only outputs mtime
|
||||
// but set the flag for a/ctime, if present in loc
|
||||
int flagEXTT = 0;
|
||||
long umtime = -1;
|
||||
long uatime = -1;
|
||||
long uctime = -1;
|
||||
if (e.mtime != null) {
|
||||
flagEXTT |= EXTT_FLAG_LMT;
|
||||
umtime = fileTimeToUnixTime(e.mtime);
|
||||
}
|
||||
if (e.atime != null) {
|
||||
flagEXTT |= EXTT_FLAG_LAT;
|
||||
uatime = fileTimeToUnixTime(e.atime);
|
||||
}
|
||||
if (e.ctime != null) {
|
||||
flagEXTT |= EXTT_FLAT_CT;
|
||||
uctime = fileTimeToUnixTime(e.ctime);
|
||||
}
|
||||
if (flagEXTT != 0) {
|
||||
// to use ntfs time if any m/a/ctime is beyond unixtime upper bound
|
||||
if (umtime > UPPER_UNIXTIME_BOUND ||
|
||||
uatime > UPPER_UNIXTIME_BOUND ||
|
||||
uctime > UPPER_UNIXTIME_BOUND) {
|
||||
elen += 36; // NTFS time total 36 bytes
|
||||
} else {
|
||||
elen += 9; // headid(2) + sz(2) + flag(1) + mtime (4)
|
||||
}
|
||||
}
|
||||
writeShort(elen);
|
||||
byte[] commentBytes;
|
||||
if (e.comment != null) {
|
||||
commentBytes = zc.getBytes(e.comment);
|
||||
writeShort(Math.min(commentBytes.length, 0xffff));
|
||||
} else {
|
||||
commentBytes = null;
|
||||
writeShort(0);
|
||||
}
|
||||
writeShort(0); // starting disk number
|
||||
writeShort(0); // internal file attributes (unused)
|
||||
writeInt(0); // external file attributes (unused)
|
||||
writeInt(offset); // relative offset of local header
|
||||
writeBytes(nameBytes, 0, nameBytes.length);
|
||||
|
||||
// take care of EXTID_ZIP64 and EXTID_EXTT
|
||||
if (hasZip64) {
|
||||
writeShort(ZIP64_EXTID);// Zip64 extra
|
||||
writeShort(elenZIP64);
|
||||
if (size == ZIP64_MAGICVAL)
|
||||
writeLong(e.size);
|
||||
if (csize == ZIP64_MAGICVAL)
|
||||
writeLong(e.csize);
|
||||
if (offset == ZIP64_MAGICVAL)
|
||||
writeLong(xentry.offset);
|
||||
}
|
||||
if (flagEXTT != 0) {
|
||||
if (umtime > UPPER_UNIXTIME_BOUND ||
|
||||
uatime > UPPER_UNIXTIME_BOUND ||
|
||||
uctime > UPPER_UNIXTIME_BOUND) {
|
||||
writeShort(EXTID_NTFS); // id
|
||||
writeShort(32); // data size
|
||||
writeInt(0); // reserved
|
||||
writeShort(0x0001); // NTFS attr tag
|
||||
writeShort(24);
|
||||
writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
|
||||
: fileTimeToWinTime(e.mtime));
|
||||
writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
|
||||
: fileTimeToWinTime(e.atime));
|
||||
writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
|
||||
: fileTimeToWinTime(e.ctime));
|
||||
} else {
|
||||
writeShort(EXTID_EXTT);
|
||||
if (e.mtime != null) {
|
||||
writeShort(5); // flag + mtime
|
||||
writeByte(flagEXTT);
|
||||
writeInt(umtime);
|
||||
} else {
|
||||
writeShort(1); // flag only
|
||||
writeByte(flagEXTT);
|
||||
}
|
||||
}
|
||||
}
|
||||
writeExtra(e.extra);
|
||||
if (commentBytes != null) {
|
||||
writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes end of central directory (END) header.
|
||||
*/
|
||||
private void writeEND(long off, long len) throws IOException {
|
||||
boolean hasZip64 = false;
|
||||
long xlen = len;
|
||||
long xoff = off;
|
||||
if (xlen >= ZIP64_MAGICVAL) {
|
||||
xlen = ZIP64_MAGICVAL;
|
||||
hasZip64 = true;
|
||||
}
|
||||
if (xoff >= ZIP64_MAGICVAL) {
|
||||
xoff = ZIP64_MAGICVAL;
|
||||
hasZip64 = true;
|
||||
}
|
||||
int count = xentries.size();
|
||||
if (count >= ZIP64_MAGICCOUNT) {
|
||||
hasZip64 |= !inhibitZip64;
|
||||
if (hasZip64) {
|
||||
count = ZIP64_MAGICCOUNT;
|
||||
}
|
||||
}
|
||||
if (hasZip64) {
|
||||
long off64 = written;
|
||||
//zip64 end of central directory record
|
||||
writeInt(ZIP64_ENDSIG); // zip64 END record signature
|
||||
writeLong(ZIP64_ENDHDR - 12); // size of zip64 end
|
||||
writeShort(45); // version made by
|
||||
writeShort(45); // version needed to extract
|
||||
writeInt(0); // number of this disk
|
||||
writeInt(0); // central directory start disk
|
||||
writeLong(xentries.size()); // number of directory entires on disk
|
||||
writeLong(xentries.size()); // number of directory entires
|
||||
writeLong(len); // length of central directory
|
||||
writeLong(off); // offset of central directory
|
||||
|
||||
//zip64 end of central directory locator
|
||||
writeInt(ZIP64_LOCSIG); // zip64 END locator signature
|
||||
writeInt(0); // zip64 END start disk
|
||||
writeLong(off64); // offset of zip64 END
|
||||
writeInt(1); // total number of disks (?)
|
||||
}
|
||||
writeInt(ENDSIG); // END record signature
|
||||
writeShort(0); // number of this disk
|
||||
writeShort(0); // central directory start disk
|
||||
writeShort(count); // number of directory entries on disk
|
||||
writeShort(count); // total number of directory entries
|
||||
writeInt(xlen); // length of central directory
|
||||
writeInt(xoff); // offset of central directory
|
||||
if (comment != null) { // zip file comment
|
||||
writeShort(comment.length);
|
||||
writeBytes(comment, 0, comment.length);
|
||||
} else {
|
||||
writeShort(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the length of extra data without EXTT and ZIP64.
|
||||
*/
|
||||
private int getExtraLen(byte[] extra) {
|
||||
if (extra == null)
|
||||
return 0;
|
||||
int skipped = 0;
|
||||
int len = extra.length;
|
||||
int off = 0;
|
||||
while (off + 4 <= len) {
|
||||
int tag = get16(extra, off);
|
||||
int sz = get16(extra, off + 2);
|
||||
if (sz < 0 || (off + 4 + sz) > len) {
|
||||
break;
|
||||
}
|
||||
if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
|
||||
skipped += (sz + 4);
|
||||
}
|
||||
off += (sz + 4);
|
||||
}
|
||||
return len - skipped;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes extra data without EXTT and ZIP64.
|
||||
*
|
||||
* Extra timestamp and ZIP64 data is handled/output separately
|
||||
* in writeLOC and writeCEN.
|
||||
*/
|
||||
private void writeExtra(byte[] extra) throws IOException {
|
||||
if (extra != null) {
|
||||
int len = extra.length;
|
||||
int off = 0;
|
||||
while (off + 4 <= len) {
|
||||
int tag = get16(extra, off);
|
||||
int sz = get16(extra, off + 2);
|
||||
if (sz < 0 || (off + 4 + sz) > len) {
|
||||
writeBytes(extra, off, len - off);
|
||||
return;
|
||||
}
|
||||
if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
|
||||
writeBytes(extra, off, sz + 4);
|
||||
}
|
||||
off += (sz + 4);
|
||||
}
|
||||
if (off < len) {
|
||||
writeBytes(extra, off, len - off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 8-bit byte to the output stream.
|
||||
*/
|
||||
private void writeByte(int v) throws IOException {
|
||||
OutputStream out = this.out;
|
||||
out.write(v & 0xff);
|
||||
written += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 16-bit short to the output stream in little-endian byte order.
|
||||
*/
|
||||
private void writeShort(int v) throws IOException {
|
||||
OutputStream out = this.out;
|
||||
out.write((v >>> 0) & 0xff);
|
||||
out.write((v >>> 8) & 0xff);
|
||||
written += 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 32-bit int to the output stream in little-endian byte order.
|
||||
*/
|
||||
private void writeInt(long v) throws IOException {
|
||||
OutputStream out = this.out;
|
||||
out.write((int)((v >>> 0) & 0xff));
|
||||
out.write((int)((v >>> 8) & 0xff));
|
||||
out.write((int)((v >>> 16) & 0xff));
|
||||
out.write((int)((v >>> 24) & 0xff));
|
||||
written += 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 64-bit int to the output stream in little-endian byte order.
|
||||
*/
|
||||
private void writeLong(long v) throws IOException {
|
||||
OutputStream out = this.out;
|
||||
out.write((int)((v >>> 0) & 0xff));
|
||||
out.write((int)((v >>> 8) & 0xff));
|
||||
out.write((int)((v >>> 16) & 0xff));
|
||||
out.write((int)((v >>> 24) & 0xff));
|
||||
out.write((int)((v >>> 32) & 0xff));
|
||||
out.write((int)((v >>> 40) & 0xff));
|
||||
out.write((int)((v >>> 48) & 0xff));
|
||||
out.write((int)((v >>> 56) & 0xff));
|
||||
written += 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes an array of bytes to the output stream.
|
||||
*/
|
||||
private void writeBytes(byte[] b, int off, int len) throws IOException {
|
||||
super.out.write(b, off, len);
|
||||
written += len;
|
||||
}
|
||||
}
|
274
src/java.base/share/classes/java/util/zip/ZipUtils.java
Normal file
274
src/java.base/share/classes/java/util/zip/ZipUtils.java
Normal file
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.zip;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.util.zip.ZipConstants.ENDHDR;
|
||||
|
||||
class ZipUtils {
|
||||
|
||||
// used to adjust values between Windows and java epoch
|
||||
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
|
||||
|
||||
// used to indicate the corresponding windows time is not available
|
||||
public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
|
||||
*/
|
||||
public static final FileTime winTimeToFileTime(long wtime) {
|
||||
return FileTime.from(wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS,
|
||||
TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts FileTime to Windows time.
|
||||
*/
|
||||
public static final long fileTimeToWinTime(FileTime ftime) {
|
||||
return (ftime.to(TimeUnit.MICROSECONDS) - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* The upper bound of the 32-bit unix time, the "year 2038 problem".
|
||||
*/
|
||||
public static final long UPPER_UNIXTIME_BOUND = 0x7fffffff;
|
||||
|
||||
/**
|
||||
* Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
|
||||
*/
|
||||
public static final FileTime unixTimeToFileTime(long utime) {
|
||||
return FileTime.from(utime, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts FileTime to "standard Unix time".
|
||||
*/
|
||||
public static final long fileTimeToUnixTime(FileTime ftime) {
|
||||
return ftime.to(TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts DOS time to Java time (number of milliseconds since epoch).
|
||||
*/
|
||||
public static long dosToJavaTime(long dtime) {
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour = (int) ((dtime >> 11) & 0x1f);
|
||||
int minute = (int) ((dtime >> 5) & 0x3f);
|
||||
int second = (int) ((dtime << 1) & 0x3e);
|
||||
if ((dtime >> 16) == 0) {
|
||||
// Interpret the 0 DOS date as 1979-11-30 for compatibility with
|
||||
// other implementations.
|
||||
year = 1979;
|
||||
month = 11;
|
||||
day = 30;
|
||||
} else {
|
||||
year = (int) (((dtime >> 25) & 0x7f) + 1980);
|
||||
month = (int) ((dtime >> 21) & 0x0f);
|
||||
day = (int) ((dtime >> 16) & 0x1f);
|
||||
}
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
|
||||
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts extended DOS time to Java time, where up to 1999 milliseconds
|
||||
* might be encoded into the upper half of the returned long.
|
||||
*
|
||||
* @param xdostime the extended DOS time value
|
||||
* @return milliseconds since epoch
|
||||
*/
|
||||
public static long extendedDosToJavaTime(long xdostime) {
|
||||
long time = dosToJavaTime(xdostime);
|
||||
return time + (xdostime >> 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Java time to DOS time.
|
||||
*/
|
||||
private static long javaToDosTime(long time) {
|
||||
Instant instant = Instant.ofEpochMilli(time);
|
||||
LocalDateTime ldt = LocalDateTime.ofInstant(
|
||||
instant, ZoneId.systemDefault());
|
||||
int year = ldt.getYear() - 1980;
|
||||
if (year < 0) {
|
||||
return (1 << 21) | (1 << 16);
|
||||
}
|
||||
return (year << 25 |
|
||||
ldt.getMonthValue() << 21 |
|
||||
ldt.getDayOfMonth() << 16 |
|
||||
ldt.getHour() << 11 |
|
||||
ldt.getMinute() << 5 |
|
||||
ldt.getSecond() >> 1) & 0xffffffffL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Java time to DOS time, encoding any milliseconds lost
|
||||
* in the conversion into the upper half of the returned long.
|
||||
*
|
||||
* @param time milliseconds since epoch
|
||||
* @return DOS time with 2s remainder encoded into upper half
|
||||
*/
|
||||
public static long javaToExtendedDosTime(long time) {
|
||||
if (time < 0) {
|
||||
return ZipEntry.DOSTIME_BEFORE_1980;
|
||||
}
|
||||
long dostime = javaToDosTime(time);
|
||||
return (dostime != ZipEntry.DOSTIME_BEFORE_1980)
|
||||
? dostime + ((time % 2000) << 32)
|
||||
: ZipEntry.DOSTIME_BEFORE_1980;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches unsigned 16-bit value from byte array at specified offset.
|
||||
* The bytes are assumed to be in Intel (little-endian) byte order.
|
||||
*/
|
||||
public static final int get16(byte b[], int off) {
|
||||
return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches unsigned 32-bit value from byte array at specified offset.
|
||||
* The bytes are assumed to be in Intel (little-endian) byte order.
|
||||
*/
|
||||
public static final long get32(byte b[], int off) {
|
||||
return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches signed 64-bit value from byte array at specified offset.
|
||||
* The bytes are assumed to be in Intel (little-endian) byte order.
|
||||
*/
|
||||
public static final long get64(byte b[], int off) {
|
||||
return get32(b, off) | (get32(b, off+4) << 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches signed 32-bit value from byte array at specified offset.
|
||||
* The bytes are assumed to be in Intel (little-endian) byte order.
|
||||
*
|
||||
*/
|
||||
public static final int get32S(byte b[], int off) {
|
||||
return (get16(b, off) | (get16(b, off+2) << 16));
|
||||
}
|
||||
|
||||
// fields access methods
|
||||
static final int CH(byte[] b, int n) {
|
||||
return b[n] & 0xff ;
|
||||
}
|
||||
|
||||
static final int SH(byte[] b, int n) {
|
||||
return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
|
||||
}
|
||||
|
||||
static final long LG(byte[] b, int n) {
|
||||
return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
|
||||
}
|
||||
|
||||
static final long LL(byte[] b, int n) {
|
||||
return (LG(b, n)) | (LG(b, n + 4) << 32);
|
||||
}
|
||||
|
||||
static final long GETSIG(byte[] b) {
|
||||
return LG(b, 0);
|
||||
}
|
||||
|
||||
// local file (LOC) header fields
|
||||
static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
|
||||
static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
|
||||
static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
|
||||
static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
|
||||
static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
|
||||
static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
|
||||
static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
|
||||
static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
|
||||
static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
|
||||
static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
|
||||
|
||||
// extra local (EXT) header fields
|
||||
static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
|
||||
static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
|
||||
static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
|
||||
|
||||
// end of central directory header (END) fields
|
||||
static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
|
||||
static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
|
||||
static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
|
||||
static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
|
||||
static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
|
||||
static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
|
||||
|
||||
// zip64 end of central directory recoder fields
|
||||
static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
|
||||
static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
|
||||
static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
|
||||
static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
|
||||
static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
|
||||
|
||||
// central directory header (CEN) fields
|
||||
static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
|
||||
static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
|
||||
static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
|
||||
static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
|
||||
static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
|
||||
static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
|
||||
static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
|
||||
static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
|
||||
static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
|
||||
static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
|
||||
static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
|
||||
static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
|
||||
static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
|
||||
static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
|
||||
static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
|
||||
static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
|
||||
|
||||
// The END header is followed by a variable length comment of size < 64k.
|
||||
static final long END_MAXLEN = 0xFFFF + ENDHDR;
|
||||
static final int READBLOCKSZ = 128;
|
||||
|
||||
/**
|
||||
* Loads zip native library, if not already laoded
|
||||
*/
|
||||
static void loadLibrary() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) {
|
||||
System.loadLibrary("zip");
|
||||
} else {
|
||||
PrivilegedAction<Void> pa = () -> { System.loadLibrary("zip"); return null; };
|
||||
AccessController.doPrivileged(pa);
|
||||
}
|
||||
}
|
||||
}
|
77
src/java.base/share/classes/java/util/zip/package-info.java
Normal file
77
src/java.base/share/classes/java/util/zip/package-info.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides classes for reading and writing the standard ZIP and GZIP file
|
||||
* formats. Also includes classes for compressing and decompressing data using
|
||||
* the DEFLATE compression algorithm, which is used by the ZIP and GZIP file
|
||||
* formats. Additionally, there are utility classes for computing the CRC-32,
|
||||
* CRC-32C and Adler-32 checksums of arbitrary input streams.
|
||||
*
|
||||
* <h2>Package Specification</h2>
|
||||
*
|
||||
* <ul>
|
||||
* <li><a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">
|
||||
* Info-ZIP Application Note 970311</a> - a detailed description of
|
||||
* the Info-ZIP format upon which the {@code java.util.zip} classes
|
||||
* are based.
|
||||
* <li><a id="zip64">An implementation may optionally support the
|
||||
* ZIP64(tm) format extensions defined by the</a>
|
||||
* <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
|
||||
* PKWARE ZIP File Format Specification</a>. The ZIP64(tm) format
|
||||
* extensions are used to overcome the size limitations of the
|
||||
* original ZIP format.
|
||||
* <li><a id="lang_encoding">APPENDIX D of</a>
|
||||
* <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
|
||||
* PKWARE ZIP File Format Specification</a> - Language Encoding Flag
|
||||
* (EFS) to encode ZIP entry filename and comment fields using UTF-8.
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc1950.txt">
|
||||
* ZLIB Compressed Data Format Specification version 3.3</a>
|
||||
*
|
||||
* <a href="http://www.ietf.org/rfc/rfc1950.txt.pdf">(pdf)</a>
|
||||
* (RFC 1950)
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc1951.txt">
|
||||
* DEFLATE Compressed Data Format Specification version 1.3</a>
|
||||
*
|
||||
* <a href="http://www.ietf.org/rfc/rfc1951.txt.pdf">(pdf)</a>
|
||||
* (RFC 1951)
|
||||
* <li><a href="http://www.ietf.org/rfc/rfc1952.txt">
|
||||
* GZIP file format specification version 4.3</a>
|
||||
*
|
||||
* <a href="http://www.ietf.org/rfc/rfc1952.txt.pdf">(pdf)</a>
|
||||
* (RFC 1952)
|
||||
* <li>CRC-32 checksum is described in RFC 1952 (above)
|
||||
* <li>CRC-32C checksum is described in
|
||||
* <a href="http://www.ietf.org/rfc/rfc3720.txt">Internet Small
|
||||
* Computer Systems Interface (iSCSI)</a>
|
||||
*
|
||||
* <a href="http://www.ietf.org/rfc/rfc3720.txt.pdf">(pdf)</a>
|
||||
* (RFC 3720)
|
||||
* <li>Adler-32 checksum is described in RFC 1950 (above)
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
package java.util.zip;
|
Loading…
Add table
Add a link
Reference in a new issue