The performance problem was mainly due to the entry insertion in the hashtable where all hash code were equals in the hashtable. I also removed a lot of unecessary Zip(Long|Short) object creation by adding static methods and suppressed a hashtable. More can be done, but I tried not to break the interface and have as less code as possible. The testcase attached in the bug report show that it is now 15% slower than Sun native code and 20% faster than Jazz libs. Now watch for Gump... PR: 31930 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277122 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -135,15 +135,15 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||||
| public byte[] getLocalFileDataData() { | public byte[] getLocalFileDataData() { | ||||
| // CRC will be added later | // CRC will be added later | ||||
| byte[] data = new byte[getLocalFileDataLength().getValue() - 4]; | byte[] data = new byte[getLocalFileDataLength().getValue() - 4]; | ||||
| System.arraycopy((new ZipShort(getMode())).getBytes(), 0, data, 0, 2); | |||||
| System.arraycopy(ZipShort.getBytes(getMode()), 0, data, 0, 2); | |||||
| byte[] linkArray = getLinkedFile().getBytes(); | byte[] linkArray = getLinkedFile().getBytes(); | ||||
| System.arraycopy((new ZipLong(linkArray.length)).getBytes(), | |||||
| System.arraycopy(ZipLong.getBytes(linkArray.length), | |||||
| 0, data, 2, 4); | 0, data, 2, 4); | ||||
| System.arraycopy((new ZipShort(getUserId())).getBytes(), | |||||
| System.arraycopy(ZipShort.getBytes(getUserId()), | |||||
| 0, data, 6, 2); | 0, data, 6, 2); | ||||
| System.arraycopy((new ZipShort(getGroupId())).getBytes(), | |||||
| System.arraycopy(ZipShort.getBytes(getGroupId()), | |||||
| 0, data, 8, 2); | 0, data, 8, 2); | ||||
| System.arraycopy(linkArray, 0, data, 10, linkArray.length); | System.arraycopy(linkArray, 0, data, 10, linkArray.length); | ||||
| @@ -153,7 +153,7 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||||
| long checksum = crc.getValue(); | long checksum = crc.getValue(); | ||||
| byte[] result = new byte[data.length + 4]; | byte[] result = new byte[data.length + 4]; | ||||
| System.arraycopy((new ZipLong(checksum)).getBytes(), 0, result, 0, 4); | |||||
| System.arraycopy(ZipLong.getBytes(checksum), 0, result, 0, 4); | |||||
| System.arraycopy(data, 0, result, 4, data.length); | System.arraycopy(data, 0, result, 4, data.length); | ||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -282,7 +282,7 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||||
| public void parseFromLocalFileData(byte[] data, int offset, int length) | public void parseFromLocalFileData(byte[] data, int offset, int length) | ||||
| throws ZipException { | throws ZipException { | ||||
| long givenChecksum = (new ZipLong(data, offset)).getValue(); | |||||
| long givenChecksum = ZipLong.getValue(data, offset); | |||||
| byte[] tmp = new byte[length - 4]; | byte[] tmp = new byte[length - 4]; | ||||
| System.arraycopy(data, offset + 4, tmp, 0, length - 4); | System.arraycopy(data, offset + 4, tmp, 0, length - 4); | ||||
| crc.reset(); | crc.reset(); | ||||
| @@ -295,10 +295,10 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||||
| + Long.toHexString(realChecksum)); | + Long.toHexString(realChecksum)); | ||||
| } | } | ||||
| int newMode = (new ZipShort(tmp, 0)).getValue(); | |||||
| byte[] linkArray = new byte[(int) (new ZipLong(tmp, 2)).getValue()]; | |||||
| uid = (new ZipShort(tmp, 6)).getValue(); | |||||
| gid = (new ZipShort(tmp, 8)).getValue(); | |||||
| int newMode = ZipShort.getValue(tmp, 0); | |||||
| byte[] linkArray = new byte[(int) ZipLong.getValue(tmp, 2)]; | |||||
| uid = ZipShort.getValue(tmp, 6); | |||||
| gid = ZipShort.getValue(tmp, 8); | |||||
| if (linkArray.length == 0) { | if (linkArray.length == 0) { | ||||
| link = ""; | link = ""; | ||||
| @@ -20,6 +20,8 @@ package org.apache.tools.zip; | |||||
| import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import java.util.Date; | |||||
| import java.util.Calendar; | |||||
| import java.util.zip.ZipException; | import java.util.zip.ZipException; | ||||
| /** | /** | ||||
| @@ -386,6 +388,24 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable { | |||||
| this.name = name; | this.name = name; | ||||
| } | } | ||||
| /** | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| public int hashCode(){ | |||||
| return getName().hashCode(); | |||||
| } | |||||
| /** | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| public boolean equals(Object o){ | |||||
| if (o instanceof ZipEntry){ | |||||
| ZipEntry other = (ZipEntry)o; | |||||
| return other.getName().equals(getName()); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | /** | ||||
| * Helper for JDK 1.1 | * Helper for JDK 1.1 | ||||
| * | * | ||||
| @@ -64,17 +64,17 @@ public class ZipFile { | |||||
| * Maps ZipEntrys to Longs, recording the offsets of the local | * Maps ZipEntrys to Longs, recording the offsets of the local | ||||
| * file headers. | * file headers. | ||||
| */ | */ | ||||
| private Hashtable entries = new Hashtable(); | |||||
| private Hashtable entries = new Hashtable(509); | |||||
| /** | /** | ||||
| * Maps String to ZipEntrys, name -> actual entry. | * Maps String to ZipEntrys, name -> actual entry. | ||||
| */ | */ | ||||
| private Hashtable nameMap = new Hashtable(); | |||||
| private Hashtable nameMap = new Hashtable(509); | |||||
| /** | |||||
| * Maps ZipEntrys to Longs, recording the offsets of the actual file data. | |||||
| */ | |||||
| private Hashtable dataOffsets = new Hashtable(); | |||||
| private static final class OffsetEntry { | |||||
| long headerOffset = -1; | |||||
| long dataOffset = - 1; | |||||
| } | |||||
| /** | /** | ||||
| * The encoding to use for filenames and the file comment. | * The encoding to use for filenames and the file comment. | ||||
| @@ -201,12 +201,13 @@ public class ZipFile { | |||||
| */ | */ | ||||
| public InputStream getInputStream(ZipEntry ze) | public InputStream getInputStream(ZipEntry ze) | ||||
| throws IOException, ZipException { | throws IOException, ZipException { | ||||
| Long start = (Long) dataOffsets.get(ze); | |||||
| if (start == null) { | |||||
| OffsetEntry offsetEntry = (OffsetEntry)entries.get(ze); | |||||
| if (offsetEntry == null){ | |||||
| return null; | return null; | ||||
| } | } | ||||
| long start = offsetEntry.dataOffset; | |||||
| BoundedInputStream bis = | BoundedInputStream bis = | ||||
| new BoundedInputStream(start.longValue(), ze.getCompressedSize()); | |||||
| new BoundedInputStream(start, ze.getCompressedSize()); | |||||
| switch (ze.getMethod()) { | switch (ze.getMethod()) { | ||||
| case ZipEntry.STORED: | case ZipEntry.STORED: | ||||
| return bis; | return bis; | ||||
| @@ -253,57 +254,66 @@ public class ZipFile { | |||||
| byte[] signatureBytes = new byte[4]; | byte[] signatureBytes = new byte[4]; | ||||
| archive.readFully(signatureBytes); | archive.readFully(signatureBytes); | ||||
| ZipLong sig = new ZipLong(signatureBytes); | |||||
| while (sig.equals(ZipOutputStream.CFH_SIG)) { | |||||
| long sig = ZipLong.getValue(signatureBytes); | |||||
| final long cfh_sig = ZipLong.getValue(ZipOutputStream.CFH_SIG); | |||||
| while (sig == cfh_sig) { | |||||
| archive.readFully(cfh); | archive.readFully(cfh); | ||||
| int off = 0; | int off = 0; | ||||
| ZipEntry ze = new ZipEntry(); | ZipEntry ze = new ZipEntry(); | ||||
| ZipShort versionMadeBy = new ZipShort(cfh, off); | |||||
| int versionMadeBy = ZipShort.getValue(cfh, off); | |||||
| off += 2; | off += 2; | ||||
| ze.setPlatform((versionMadeBy.getValue() >> 8) & 0x0F); | |||||
| ze.setPlatform((versionMadeBy >> 8) & 0x0F); | |||||
| off += 4; // skip version info and general purpose byte | off += 4; // skip version info and general purpose byte | ||||
| ze.setMethod((new ZipShort(cfh, off)).getValue()); | |||||
| ze.setMethod(ZipShort.getValue(cfh, off)); | |||||
| off += 2; | off += 2; | ||||
| ze.setTime(fromDosTime(new ZipLong(cfh, off)).getTime()); | |||||
| // FIXME this is actually not very cpu cycles friendly as we are converting from | |||||
| // dos to java while the underlying Sun implementation will convert | |||||
| // from java to dos time for internal storage... | |||||
| long time = dosToJavaTime(ZipLong.getValue(cfh, off)); | |||||
| ze.setTime(time); | |||||
| off += 4; | off += 4; | ||||
| ze.setCrc((new ZipLong(cfh, off)).getValue()); | |||||
| ze.setCrc(ZipLong.getValue(cfh, off)); | |||||
| off += 4; | off += 4; | ||||
| ze.setCompressedSize((new ZipLong(cfh, off)).getValue()); | |||||
| ze.setCompressedSize(ZipLong.getValue(cfh, off)); | |||||
| off += 4; | off += 4; | ||||
| ze.setSize((new ZipLong(cfh, off)).getValue()); | |||||
| ze.setSize(ZipLong.getValue(cfh, off)); | |||||
| off += 4; | off += 4; | ||||
| int fileNameLen = (new ZipShort(cfh, off)).getValue(); | |||||
| int fileNameLen = ZipShort.getValue(cfh, off); | |||||
| off += 2; | off += 2; | ||||
| int extraLen = (new ZipShort(cfh, off)).getValue(); | |||||
| int extraLen = ZipShort.getValue(cfh, off); | |||||
| off += 2; | off += 2; | ||||
| int commentLen = (new ZipShort(cfh, off)).getValue(); | |||||
| int commentLen = ZipShort.getValue(cfh, off); | |||||
| off += 2; | off += 2; | ||||
| off += 2; // disk number | off += 2; // disk number | ||||
| ze.setInternalAttributes((new ZipShort(cfh, off)).getValue()); | |||||
| ze.setInternalAttributes(ZipShort.getValue(cfh, off)); | |||||
| off += 2; | off += 2; | ||||
| ze.setExternalAttributes((new ZipLong(cfh, off)).getValue()); | |||||
| ze.setExternalAttributes(ZipLong.getValue(cfh, off)); | |||||
| off += 4; | off += 4; | ||||
| // LFH offset | |||||
| entries.put(ze, new Long((new ZipLong(cfh, off)).getValue())); | |||||
| byte[] fileName = new byte[fileNameLen]; | byte[] fileName = new byte[fileNameLen]; | ||||
| archive.readFully(fileName); | archive.readFully(fileName); | ||||
| ze.setName(getString(fileName)); | ze.setName(getString(fileName)); | ||||
| // LFH offset, | |||||
| OffsetEntry offset = new OffsetEntry(); | |||||
| offset.headerOffset = ZipLong.getValue(cfh, off); | |||||
| // data offset will be filled later | |||||
| entries.put(ze, offset); | |||||
| nameMap.put(ze.getName(), ze); | nameMap.put(ze.getName(), ze); | ||||
| archive.skipBytes(extraLen); | archive.skipBytes(extraLen); | ||||
| @@ -313,7 +323,7 @@ public class ZipFile { | |||||
| ze.setComment(getString(comment)); | ze.setComment(getString(comment)); | ||||
| archive.readFully(signatureBytes); | archive.readFully(signatureBytes); | ||||
| sig = new ZipLong(signatureBytes); | |||||
| sig = ZipLong.getValue(signatureBytes); | |||||
| } | } | ||||
| } | } | ||||
| @@ -352,7 +362,7 @@ public class ZipFile { | |||||
| throws IOException { | throws IOException { | ||||
| long off = archive.length() - MIN_EOCD_SIZE; | long off = archive.length() - MIN_EOCD_SIZE; | ||||
| archive.seek(off); | archive.seek(off); | ||||
| byte[] sig = ZipOutputStream.EOCD_SIG.getBytes(); | |||||
| byte[] sig = ZipOutputStream.EOCD_SIG; | |||||
| int curr = archive.read(); | int curr = archive.read(); | ||||
| boolean found = false; | boolean found = false; | ||||
| while (curr != -1) { | while (curr != -1) { | ||||
| @@ -378,7 +388,7 @@ public class ZipFile { | |||||
| archive.seek(off + CFD_LOCATOR_OFFSET); | archive.seek(off + CFD_LOCATOR_OFFSET); | ||||
| byte[] cfdOffset = new byte[4]; | byte[] cfdOffset = new byte[4]; | ||||
| archive.readFully(cfdOffset); | archive.readFully(cfdOffset); | ||||
| archive.seek((new ZipLong(cfdOffset)).getValue()); | |||||
| archive.seek(ZipLong.getValue(cfdOffset)); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -408,31 +418,42 @@ public class ZipFile { | |||||
| Enumeration e = getEntries(); | Enumeration e = getEntries(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| ZipEntry ze = (ZipEntry) e.nextElement(); | ZipEntry ze = (ZipEntry) e.nextElement(); | ||||
| long offset = ((Long) entries.get(ze)).longValue(); | |||||
| OffsetEntry offsetEntry = (OffsetEntry)entries.get(ze); | |||||
| long offset = offsetEntry.headerOffset; | |||||
| archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH); | archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH); | ||||
| byte[] b = new byte[2]; | byte[] b = new byte[2]; | ||||
| archive.readFully(b); | archive.readFully(b); | ||||
| int fileNameLen = (new ZipShort(b)).getValue(); | |||||
| int fileNameLen = ZipShort.getValue(b); | |||||
| archive.readFully(b); | archive.readFully(b); | ||||
| int extraFieldLen = (new ZipShort(b)).getValue(); | |||||
| int extraFieldLen = ZipShort.getValue(b); | |||||
| archive.skipBytes(fileNameLen); | archive.skipBytes(fileNameLen); | ||||
| byte[] localExtraData = new byte[extraFieldLen]; | byte[] localExtraData = new byte[extraFieldLen]; | ||||
| archive.readFully(localExtraData); | archive.readFully(localExtraData); | ||||
| ze.setExtra(localExtraData); | ze.setExtra(localExtraData); | ||||
| dataOffsets.put(ze, | |||||
| /*dataOffsets.put(ze, | |||||
| new Long(offset + LFH_OFFSET_FOR_FILENAME_LENGTH | new Long(offset + LFH_OFFSET_FOR_FILENAME_LENGTH | ||||
| + 2 + 2 + fileNameLen + extraFieldLen)); | + 2 + 2 + fileNameLen + extraFieldLen)); | ||||
| */ | |||||
| offsetEntry.dataOffset = offset + LFH_OFFSET_FOR_FILENAME_LENGTH | |||||
| + 2 + 2 + fileNameLen + extraFieldLen; | |||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Convert a DOS date/time field to a Date object. | * Convert a DOS date/time field to a Date object. | ||||
| * | * | ||||
| * @param l contains the stored DOS time. | |||||
| * @param zipDosTime contains the stored DOS time. | |||||
| * @return a Date instance corresponding to the given time. | * @return a Date instance corresponding to the given time. | ||||
| */ | */ | ||||
| protected static Date fromDosTime(ZipLong l) { | |||||
| long dosTime = l.getValue(); | |||||
| protected static Date fromDosTime(ZipLong zipDosTime) { | |||||
| long dosTime = zipDosTime.getValue(); | |||||
| return new Date(dosToJavaTime(dosTime)); | |||||
| } | |||||
| /* | |||||
| * Converts DOS time to Java time (number of milliseconds since epoch). | |||||
| */ | |||||
| private static long dosToJavaTime(long dosTime) { | |||||
| Calendar cal = Calendar.getInstance(); | Calendar cal = Calendar.getInstance(); | ||||
| cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980); | cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980); | ||||
| cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1); | cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1); | ||||
| @@ -440,9 +461,10 @@ public class ZipFile { | |||||
| cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f); | cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f); | ||||
| cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f); | cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f); | ||||
| cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e); | cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e); | ||||
| return cal.getTime(); | |||||
| return cal.getTimeInMillis(); | |||||
| } | } | ||||
| /** | /** | ||||
| * Retrieve a String from the given bytes using the encoding set | * Retrieve a String from the given bytes using the encoding set | ||||
| * for this ZipFile. | * for this ZipFile. | ||||
| @@ -29,7 +29,6 @@ public final class ZipLong implements Cloneable { | |||||
| /** | /** | ||||
| * Create instance from a number. | * Create instance from a number. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public ZipLong(long value) { | public ZipLong(long value) { | ||||
| @@ -38,7 +37,6 @@ public final class ZipLong implements Cloneable { | |||||
| /** | /** | ||||
| * Create instance from bytes. | * Create instance from bytes. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public ZipLong (byte[] bytes) { | public ZipLong (byte[] bytes) { | ||||
| @@ -47,22 +45,34 @@ public final class ZipLong implements Cloneable { | |||||
| /** | /** | ||||
| * Create instance from the four bytes starting at offset. | * Create instance from the four bytes starting at offset. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public ZipLong (byte[] bytes, int offset) { | public ZipLong (byte[] bytes, int offset) { | ||||
| value = (bytes[offset + 3] << 24) & 0xFF000000L; | |||||
| value += (bytes[offset + 2] << 16) & 0xFF0000; | |||||
| value += (bytes[offset + 1] << 8) & 0xFF00; | |||||
| value += (bytes[offset] & 0xFF); | |||||
| value = ZipLong.getValue(bytes, offset); | |||||
| } | } | ||||
| /** | /** | ||||
| * Get value as two bytes in big endian byte order. | |||||
| * | |||||
| * Get value as four bytes in big endian byte order. | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public byte[] getBytes() { | public byte[] getBytes() { | ||||
| return ZipLong.getBytes(value); | |||||
| } | |||||
| /** | |||||
| * Get value as Java int. | |||||
| * @since 1.1 | |||||
| */ | |||||
| public long getValue() { | |||||
| return value; | |||||
| } | |||||
| /** | |||||
| * Get value as four bytes in big endian byte order. | |||||
| * @param value the value to convert | |||||
| * @return value as four bytes in big endian byte order | |||||
| */ | |||||
| public static byte[] getBytes(long value){ | |||||
| byte[] result = new byte[4]; | byte[] result = new byte[4]; | ||||
| result[0] = (byte) ((value & 0xFF)); | result[0] = (byte) ((value & 0xFF)); | ||||
| result[1] = (byte) ((value & 0xFF00) >> 8); | result[1] = (byte) ((value & 0xFF00) >> 8); | ||||
| @@ -72,14 +82,28 @@ public final class ZipLong implements Cloneable { | |||||
| } | } | ||||
| /** | /** | ||||
| * Get value as Java int. | |||||
| * | |||||
| * @since 1.1 | |||||
| * Helper method to get the value as a java long from four bytes starting at given array offset | |||||
| * @param bytes the array of bytes | |||||
| * @param offset the offset to start | |||||
| * @return the correspondanding java int value | |||||
| */ | */ | ||||
| public long getValue() { | |||||
| public static long getValue(byte[] bytes, int offset){ | |||||
| long value = (bytes[offset + 3] << 24) & 0xFF000000L; | |||||
| value += (bytes[offset + 2] << 16) & 0xFF0000; | |||||
| value += (bytes[offset + 1] << 8) & 0xFF00; | |||||
| value += (bytes[offset] & 0xFF); | |||||
| return value; | return value; | ||||
| } | } | ||||
| /** | |||||
| * Helper method to get the value as a java long from a four-byte array | |||||
| * @param bytes the array of bytes | |||||
| * @return the correspondanding java long value | |||||
| */ | |||||
| public static long getValue(byte[] bytes){ | |||||
| return getValue(bytes, 0); | |||||
| } | |||||
| /** | /** | ||||
| * Override to make two instances with same value equal. | * Override to make two instances with same value equal. | ||||
| * | * | ||||
| @@ -27,6 +27,7 @@ import java.io.UnsupportedEncodingException; | |||||
| import java.util.Date; | import java.util.Date; | ||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import java.util.Calendar; | |||||
| import java.util.zip.CRC32; | import java.util.zip.CRC32; | ||||
| import java.util.zip.Deflater; | import java.util.zip.Deflater; | ||||
| import java.util.zip.ZipException; | import java.util.zip.ZipException; | ||||
| @@ -131,14 +132,14 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| private ZipLong cdOffset = new ZipLong(0); | |||||
| private long cdOffset = 0; | |||||
| /** | /** | ||||
| * Length of central directory. | * Length of central directory. | ||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| private ZipLong cdLength = new ZipLong(0); | |||||
| private long cdLength = 0; | |||||
| /** | /** | ||||
| * Helper, a 0 as ZipShort. | * Helper, a 0 as ZipShort. | ||||
| @@ -297,11 +298,11 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| */ | */ | ||||
| public void finish() throws IOException { | public void finish() throws IOException { | ||||
| closeEntry(); | closeEntry(); | ||||
| cdOffset = new ZipLong(written); | |||||
| cdOffset = written; | |||||
| for (int i = 0; i < entries.size(); i++) { | for (int i = 0; i < entries.size(); i++) { | ||||
| writeCentralFileHeader((ZipEntry) entries.elementAt(i)); | writeCentralFileHeader((ZipEntry) entries.elementAt(i)); | ||||
| } | } | ||||
| cdLength = new ZipLong(written - cdOffset.getValue()); | |||||
| cdLength = written - cdOffset; | |||||
| writeCentralDirectoryEnd(); | writeCentralDirectoryEnd(); | ||||
| offsets.clear(); | offsets.clear(); | ||||
| entries.removeAllElements(); | entries.removeAllElements(); | ||||
| @@ -363,9 +364,9 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| long save = raf.getFilePointer(); | long save = raf.getFilePointer(); | ||||
| raf.seek(localDataStart); | raf.seek(localDataStart); | ||||
| writeOut((new ZipLong(entry.getCrc())).getBytes()); | |||||
| writeOut((new ZipLong(entry.getCompressedSize())).getBytes()); | |||||
| writeOut((new ZipLong(entry.getSize())).getBytes()); | |||||
| writeOut(ZipLong.getBytes(entry.getCrc())); | |||||
| writeOut(ZipLong.getBytes(entry.getCompressedSize())); | |||||
| writeOut(ZipLong.getBytes(entry.getSize())); | |||||
| raf.seek(save); | raf.seek(save); | ||||
| } | } | ||||
| @@ -517,25 +518,25 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected static final ZipLong LFH_SIG = new ZipLong(0X04034B50L); | |||||
| protected static final byte[] LFH_SIG = ZipLong.getBytes(0X04034B50L); | |||||
| /** | /** | ||||
| * data descriptor signature | * data descriptor signature | ||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected static final ZipLong DD_SIG = new ZipLong(0X08074B50L); | |||||
| protected static final byte[] DD_SIG = ZipLong.getBytes(0X08074B50L); | |||||
| /** | /** | ||||
| * central file header signature | * central file header signature | ||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected static final ZipLong CFH_SIG = new ZipLong(0X02014B50L); | |||||
| protected static final byte[] CFH_SIG = ZipLong.getBytes(0X02014B50L); | |||||
| /** | /** | ||||
| * end of central dir signature | * end of central dir signature | ||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected static final ZipLong EOCD_SIG = new ZipLong(0X06054B50L); | |||||
| protected static final byte[] EOCD_SIG = ZipLong.getBytes(0X06054B50L); | |||||
| /** | /** | ||||
| * Writes next block of compressed data to the output stream. | * Writes next block of compressed data to the output stream. | ||||
| @@ -555,9 +556,9 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected void writeLocalFileHeader(ZipEntry ze) throws IOException { | protected void writeLocalFileHeader(ZipEntry ze) throws IOException { | ||||
| offsets.put(ze, new ZipLong(written)); | |||||
| offsets.put(ze, ZipLong.getBytes(written)); | |||||
| writeOut(LFH_SIG.getBytes()); | |||||
| writeOut(LFH_SIG); | |||||
| written += 4; | written += 4; | ||||
| // version needed to extract | // version needed to extract | ||||
| @@ -565,18 +566,18 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| if (ze.getMethod() == DEFLATED && raf == null) { | if (ze.getMethod() == DEFLATED && raf == null) { | ||||
| // requires version 2 as we are going to store length info | // requires version 2 as we are going to store length info | ||||
| // in the data descriptor | // in the data descriptor | ||||
| writeOut((new ZipShort(20)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(20)); | |||||
| // bit3 set to signal, we use a data descriptor | // bit3 set to signal, we use a data descriptor | ||||
| writeOut((new ZipShort(8)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(8)); | |||||
| } else { | } else { | ||||
| writeOut((new ZipShort(10)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(10)); | |||||
| writeOut(ZERO); | writeOut(ZERO); | ||||
| } | } | ||||
| written += 4; | written += 4; | ||||
| // compression method | // compression method | ||||
| writeOut((new ZipShort(ze.getMethod())).getBytes()); | |||||
| writeOut(ZipShort.getBytes(ze.getMethod())); | |||||
| written += 2; | written += 2; | ||||
| // last mod. time and date | // last mod. time and date | ||||
| @@ -592,20 +593,20 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| writeOut(LZERO); | writeOut(LZERO); | ||||
| writeOut(LZERO); | writeOut(LZERO); | ||||
| } else { | } else { | ||||
| writeOut((new ZipLong(ze.getCrc())).getBytes()); | |||||
| writeOut((new ZipLong(ze.getSize())).getBytes()); | |||||
| writeOut((new ZipLong(ze.getSize())).getBytes()); | |||||
| writeOut(ZipLong.getBytes(ze.getCrc())); | |||||
| writeOut(ZipLong.getBytes(ze.getSize())); | |||||
| writeOut(ZipLong.getBytes(ze.getSize())); | |||||
| } | } | ||||
| written += 12; | written += 12; | ||||
| // file name length | // file name length | ||||
| byte[] name = getBytes(ze.getName()); | byte[] name = getBytes(ze.getName()); | ||||
| writeOut((new ZipShort(name.length)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(name.length)); | |||||
| written += 2; | written += 2; | ||||
| // extra field length | // extra field length | ||||
| byte[] extra = ze.getLocalFileDataExtra(); | byte[] extra = ze.getLocalFileDataExtra(); | ||||
| writeOut((new ZipShort(extra.length)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(extra.length)); | |||||
| written += 2; | written += 2; | ||||
| // file name | // file name | ||||
| @@ -628,10 +629,10 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| if (ze.getMethod() != DEFLATED || raf != null) { | if (ze.getMethod() != DEFLATED || raf != null) { | ||||
| return; | return; | ||||
| } | } | ||||
| writeOut(DD_SIG.getBytes()); | |||||
| writeOut((new ZipLong(entry.getCrc())).getBytes()); | |||||
| writeOut((new ZipLong(entry.getCompressedSize())).getBytes()); | |||||
| writeOut((new ZipLong(entry.getSize())).getBytes()); | |||||
| writeOut(DD_SIG); | |||||
| writeOut(ZipLong.getBytes(entry.getCrc())); | |||||
| writeOut(ZipLong.getBytes(entry.getCompressedSize())); | |||||
| writeOut(ZipLong.getBytes(entry.getSize())); | |||||
| written += 16; | written += 16; | ||||
| } | } | ||||
| @@ -641,11 +642,11 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected void writeCentralFileHeader(ZipEntry ze) throws IOException { | protected void writeCentralFileHeader(ZipEntry ze) throws IOException { | ||||
| writeOut(CFH_SIG.getBytes()); | |||||
| writeOut(CFH_SIG); | |||||
| written += 4; | written += 4; | ||||
| // version made by | // version made by | ||||
| writeOut((new ZipShort((ze.getPlatform() << 8) | 20)).getBytes()); | |||||
| writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20)); | |||||
| written += 2; | written += 2; | ||||
| // version needed to extract | // version needed to extract | ||||
| @@ -653,18 +654,18 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| if (ze.getMethod() == DEFLATED && raf == null) { | if (ze.getMethod() == DEFLATED && raf == null) { | ||||
| // requires version 2 as we are going to store length info | // requires version 2 as we are going to store length info | ||||
| // in the data descriptor | // in the data descriptor | ||||
| writeOut((new ZipShort(20)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(20)); | |||||
| // bit3 set to signal, we use a data descriptor | // bit3 set to signal, we use a data descriptor | ||||
| writeOut((new ZipShort(8)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(8)); | |||||
| } else { | } else { | ||||
| writeOut((new ZipShort(10)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(10)); | |||||
| writeOut(ZERO); | writeOut(ZERO); | ||||
| } | } | ||||
| written += 4; | written += 4; | ||||
| // compression method | // compression method | ||||
| writeOut((new ZipShort(ze.getMethod())).getBytes()); | |||||
| writeOut(ZipShort.getBytes(ze.getMethod())); | |||||
| written += 2; | written += 2; | ||||
| // last mod. time and date | // last mod. time and date | ||||
| @@ -674,19 +675,19 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| // CRC | // CRC | ||||
| // compressed length | // compressed length | ||||
| // uncompressed length | // uncompressed length | ||||
| writeOut((new ZipLong(ze.getCrc())).getBytes()); | |||||
| writeOut((new ZipLong(ze.getCompressedSize())).getBytes()); | |||||
| writeOut((new ZipLong(ze.getSize())).getBytes()); | |||||
| writeOut(ZipLong.getBytes(ze.getCrc())); | |||||
| writeOut(ZipLong.getBytes(ze.getCompressedSize())); | |||||
| writeOut(ZipLong.getBytes(ze.getSize())); | |||||
| written += 12; | written += 12; | ||||
| // file name length | // file name length | ||||
| byte[] name = getBytes(ze.getName()); | byte[] name = getBytes(ze.getName()); | ||||
| writeOut((new ZipShort(name.length)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(name.length)); | |||||
| written += 2; | written += 2; | ||||
| // extra field length | // extra field length | ||||
| byte[] extra = ze.getCentralDirectoryExtra(); | byte[] extra = ze.getCentralDirectoryExtra(); | ||||
| writeOut((new ZipShort(extra.length)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(extra.length)); | |||||
| written += 2; | written += 2; | ||||
| // file comment length | // file comment length | ||||
| @@ -695,7 +696,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| comm = ""; | comm = ""; | ||||
| } | } | ||||
| byte[] commentB = getBytes(comm); | byte[] commentB = getBytes(comm); | ||||
| writeOut((new ZipShort(commentB.length)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(commentB.length)); | |||||
| written += 2; | written += 2; | ||||
| // disk number start | // disk number start | ||||
| @@ -703,15 +704,15 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| written += 2; | written += 2; | ||||
| // internal file attributes | // internal file attributes | ||||
| writeOut((new ZipShort(ze.getInternalAttributes())).getBytes()); | |||||
| writeOut(ZipShort.getBytes(ze.getInternalAttributes())); | |||||
| written += 2; | written += 2; | ||||
| // external file attributes | // external file attributes | ||||
| writeOut((new ZipLong(ze.getExternalAttributes())).getBytes()); | |||||
| writeOut(ZipLong.getBytes(ze.getExternalAttributes())); | |||||
| written += 4; | written += 4; | ||||
| // relative offset of LFH | // relative offset of LFH | ||||
| writeOut(((ZipLong) offsets.get(ze)).getBytes()); | |||||
| writeOut((byte[]) offsets.get(ze)); | |||||
| written += 4; | written += 4; | ||||
| // file name | // file name | ||||
| @@ -733,24 +734,24 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| protected void writeCentralDirectoryEnd() throws IOException { | protected void writeCentralDirectoryEnd() throws IOException { | ||||
| writeOut(EOCD_SIG.getBytes()); | |||||
| writeOut(EOCD_SIG); | |||||
| // disk numbers | // disk numbers | ||||
| writeOut(ZERO); | writeOut(ZERO); | ||||
| writeOut(ZERO); | writeOut(ZERO); | ||||
| // number of entries | // number of entries | ||||
| byte[] num = (new ZipShort(entries.size())).getBytes(); | |||||
| byte[] num = ZipShort.getBytes(entries.size()); | |||||
| writeOut(num); | writeOut(num); | ||||
| writeOut(num); | writeOut(num); | ||||
| // length and location of CD | // length and location of CD | ||||
| writeOut(cdLength.getBytes()); | |||||
| writeOut(cdOffset.getBytes()); | |||||
| writeOut(ZipLong.getBytes(cdLength)); | |||||
| writeOut(ZipLong.getBytes(cdOffset)); | |||||
| // ZIP file comment | // ZIP file comment | ||||
| byte[] data = getBytes(comment); | byte[] data = getBytes(comment); | ||||
| writeOut((new ZipShort(data.length)).getBytes()); | |||||
| writeOut(ZipShort.getBytes(data.length)); | |||||
| writeOut(data); | writeOut(data); | ||||
| } | } | ||||
| @@ -759,7 +760,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| * | * | ||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| private static final ZipLong DOS_TIME_MIN = new ZipLong(0x00002100L); | |||||
| private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L); | |||||
| /** | /** | ||||
| * Convert a Date object to a DOS date/time field. | * Convert a Date object to a DOS date/time field. | ||||
| @@ -781,7 +782,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| Date time = new Date(t); | Date time = new Date(t); | ||||
| int year = time.getYear() + 1900; | int year = time.getYear() + 1900; | ||||
| if (year < 1980) { | if (year < 1980) { | ||||
| return DOS_TIME_MIN.getBytes(); | |||||
| return DOS_TIME_MIN; | |||||
| } | } | ||||
| int month = time.getMonth() + 1; | int month = time.getMonth() + 1; | ||||
| long value = ((year - 1980) << 25) | long value = ((year - 1980) << 25) | ||||
| @@ -790,12 +791,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||||
| | (time.getHours() << 11) | | (time.getHours() << 11) | ||||
| | (time.getMinutes() << 5) | | (time.getMinutes() << 5) | ||||
| | (time.getSeconds() >> 1); | | (time.getSeconds() >> 1); | ||||
| byte[] result = new byte[4]; | |||||
| result[0] = (byte) ((value & 0xFF)); | |||||
| result[1] = (byte) ((value & 0xFF00) >> 8); | |||||
| result[2] = (byte) ((value & 0xFF0000) >> 16); | |||||
| result[3] = (byte) ((value & 0xFF000000L) >> 24); | |||||
| return result; | |||||
| return ZipLong.getBytes(value); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -38,7 +38,6 @@ public final class ZipShort implements Cloneable { | |||||
| /** | /** | ||||
| * Create instance from bytes. | * Create instance from bytes. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public ZipShort (byte[] bytes) { | public ZipShort (byte[] bytes) { | ||||
| @@ -47,17 +46,14 @@ public final class ZipShort implements Cloneable { | |||||
| /** | /** | ||||
| * Create instance from the two bytes starting at offset. | * Create instance from the two bytes starting at offset. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public ZipShort (byte[] bytes, int offset) { | public ZipShort (byte[] bytes, int offset) { | ||||
| value = (bytes[offset + 1] << 8) & 0xFF00; | |||||
| value += (bytes[offset] & 0xFF); | |||||
| value = ZipShort.getValue(bytes, offset); | |||||
| } | } | ||||
| /** | /** | ||||
| * Get value as two bytes in big endian byte order. | * Get value as two bytes in big endian byte order. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public byte[] getBytes() { | public byte[] getBytes() { | ||||
| @@ -69,13 +65,43 @@ public final class ZipShort implements Cloneable { | |||||
| /** | /** | ||||
| * Get value as Java int. | * Get value as Java int. | ||||
| * | |||||
| * @since 1.1 | * @since 1.1 | ||||
| */ | */ | ||||
| public int getValue() { | public int getValue() { | ||||
| return value; | return value; | ||||
| } | } | ||||
| /** | |||||
| * Get value as two bytes in big endian byte order. | |||||
| */ | |||||
| public static byte[] getBytes(int value){ | |||||
| byte[] result = new byte[2]; | |||||
| result[0] = (byte) (value & 0xFF); | |||||
| result[1] = (byte) ((value & 0xFF00) >> 8); | |||||
| return result; | |||||
| } | |||||
| /** | |||||
| * Helper method to get the value as a java int from two bytes starting at given array offset | |||||
| * @param bytes the array of bytes | |||||
| * @param offset the offset to start | |||||
| * @return the correspondanding java int value | |||||
| */ | |||||
| public static int getValue(byte[] bytes, int offset){ | |||||
| int value = (bytes[offset + 1] << 8) & 0xFF00; | |||||
| value += (bytes[offset] & 0xFF); | |||||
| return value; | |||||
| } | |||||
| /** | |||||
| * Helper method to get the value as a java int from a two-byte array | |||||
| * @param bytes the array of bytes | |||||
| * @return the correspondanding java int value | |||||
| */ | |||||
| public static int getValue(byte[] bytes){ | |||||
| return getValue(bytes, 0); | |||||
| } | |||||
| /** | /** | ||||
| * Override to make two instances with same value equal. | * Override to make two instances with same value equal. | ||||
| * | * | ||||