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() { | |||
| // CRC will be added later | |||
| 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(); | |||
| System.arraycopy((new ZipLong(linkArray.length)).getBytes(), | |||
| System.arraycopy(ZipLong.getBytes(linkArray.length), | |||
| 0, data, 2, 4); | |||
| System.arraycopy((new ZipShort(getUserId())).getBytes(), | |||
| System.arraycopy(ZipShort.getBytes(getUserId()), | |||
| 0, data, 6, 2); | |||
| System.arraycopy((new ZipShort(getGroupId())).getBytes(), | |||
| System.arraycopy(ZipShort.getBytes(getGroupId()), | |||
| 0, data, 8, 2); | |||
| System.arraycopy(linkArray, 0, data, 10, linkArray.length); | |||
| @@ -153,7 +153,7 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||
| long checksum = crc.getValue(); | |||
| 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); | |||
| return result; | |||
| } | |||
| @@ -282,7 +282,7 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||
| public void parseFromLocalFileData(byte[] data, int offset, int length) | |||
| throws ZipException { | |||
| long givenChecksum = (new ZipLong(data, offset)).getValue(); | |||
| long givenChecksum = ZipLong.getValue(data, offset); | |||
| byte[] tmp = new byte[length - 4]; | |||
| System.arraycopy(data, offset + 4, tmp, 0, length - 4); | |||
| crc.reset(); | |||
| @@ -295,10 +295,10 @@ public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { | |||
| + 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) { | |||
| link = ""; | |||
| @@ -20,6 +20,8 @@ package org.apache.tools.zip; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Vector; | |||
| import java.util.Date; | |||
| import java.util.Calendar; | |||
| import java.util.zip.ZipException; | |||
| /** | |||
| @@ -386,6 +388,24 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable { | |||
| 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 | |||
| * | |||
| @@ -64,17 +64,17 @@ public class ZipFile { | |||
| * Maps ZipEntrys to Longs, recording the offsets of the local | |||
| * file headers. | |||
| */ | |||
| private Hashtable entries = new Hashtable(); | |||
| private Hashtable entries = new Hashtable(509); | |||
| /** | |||
| * 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. | |||
| @@ -201,12 +201,13 @@ public class ZipFile { | |||
| */ | |||
| public InputStream getInputStream(ZipEntry ze) | |||
| throws IOException, ZipException { | |||
| Long start = (Long) dataOffsets.get(ze); | |||
| if (start == null) { | |||
| OffsetEntry offsetEntry = (OffsetEntry)entries.get(ze); | |||
| if (offsetEntry == null){ | |||
| return null; | |||
| } | |||
| long start = offsetEntry.dataOffset; | |||
| BoundedInputStream bis = | |||
| new BoundedInputStream(start.longValue(), ze.getCompressedSize()); | |||
| new BoundedInputStream(start, ze.getCompressedSize()); | |||
| switch (ze.getMethod()) { | |||
| case ZipEntry.STORED: | |||
| return bis; | |||
| @@ -253,57 +254,66 @@ public class ZipFile { | |||
| byte[] signatureBytes = new byte[4]; | |||
| 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); | |||
| int off = 0; | |||
| ZipEntry ze = new ZipEntry(); | |||
| ZipShort versionMadeBy = new ZipShort(cfh, off); | |||
| int versionMadeBy = ZipShort.getValue(cfh, off); | |||
| off += 2; | |||
| ze.setPlatform((versionMadeBy.getValue() >> 8) & 0x0F); | |||
| ze.setPlatform((versionMadeBy >> 8) & 0x0F); | |||
| off += 4; // skip version info and general purpose byte | |||
| ze.setMethod((new ZipShort(cfh, off)).getValue()); | |||
| ze.setMethod(ZipShort.getValue(cfh, off)); | |||
| 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; | |||
| ze.setCrc((new ZipLong(cfh, off)).getValue()); | |||
| ze.setCrc(ZipLong.getValue(cfh, off)); | |||
| off += 4; | |||
| ze.setCompressedSize((new ZipLong(cfh, off)).getValue()); | |||
| ze.setCompressedSize(ZipLong.getValue(cfh, off)); | |||
| off += 4; | |||
| ze.setSize((new ZipLong(cfh, off)).getValue()); | |||
| ze.setSize(ZipLong.getValue(cfh, off)); | |||
| off += 4; | |||
| int fileNameLen = (new ZipShort(cfh, off)).getValue(); | |||
| int fileNameLen = ZipShort.getValue(cfh, off); | |||
| off += 2; | |||
| int extraLen = (new ZipShort(cfh, off)).getValue(); | |||
| int extraLen = ZipShort.getValue(cfh, off); | |||
| off += 2; | |||
| int commentLen = (new ZipShort(cfh, off)).getValue(); | |||
| int commentLen = ZipShort.getValue(cfh, off); | |||
| off += 2; | |||
| off += 2; // disk number | |||
| ze.setInternalAttributes((new ZipShort(cfh, off)).getValue()); | |||
| ze.setInternalAttributes(ZipShort.getValue(cfh, off)); | |||
| off += 2; | |||
| ze.setExternalAttributes((new ZipLong(cfh, off)).getValue()); | |||
| ze.setExternalAttributes(ZipLong.getValue(cfh, off)); | |||
| off += 4; | |||
| // LFH offset | |||
| entries.put(ze, new Long((new ZipLong(cfh, off)).getValue())); | |||
| byte[] fileName = new byte[fileNameLen]; | |||
| archive.readFully(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); | |||
| archive.skipBytes(extraLen); | |||
| @@ -313,7 +323,7 @@ public class ZipFile { | |||
| ze.setComment(getString(comment)); | |||
| archive.readFully(signatureBytes); | |||
| sig = new ZipLong(signatureBytes); | |||
| sig = ZipLong.getValue(signatureBytes); | |||
| } | |||
| } | |||
| @@ -352,7 +362,7 @@ public class ZipFile { | |||
| throws IOException { | |||
| long off = archive.length() - MIN_EOCD_SIZE; | |||
| archive.seek(off); | |||
| byte[] sig = ZipOutputStream.EOCD_SIG.getBytes(); | |||
| byte[] sig = ZipOutputStream.EOCD_SIG; | |||
| int curr = archive.read(); | |||
| boolean found = false; | |||
| while (curr != -1) { | |||
| @@ -378,7 +388,7 @@ public class ZipFile { | |||
| archive.seek(off + CFD_LOCATOR_OFFSET); | |||
| byte[] cfdOffset = new byte[4]; | |||
| archive.readFully(cfdOffset); | |||
| archive.seek((new ZipLong(cfdOffset)).getValue()); | |||
| archive.seek(ZipLong.getValue(cfdOffset)); | |||
| } | |||
| /** | |||
| @@ -408,31 +418,42 @@ public class ZipFile { | |||
| Enumeration e = getEntries(); | |||
| while (e.hasMoreElements()) { | |||
| 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); | |||
| byte[] b = new byte[2]; | |||
| archive.readFully(b); | |||
| int fileNameLen = (new ZipShort(b)).getValue(); | |||
| int fileNameLen = ZipShort.getValue(b); | |||
| archive.readFully(b); | |||
| int extraFieldLen = (new ZipShort(b)).getValue(); | |||
| int extraFieldLen = ZipShort.getValue(b); | |||
| archive.skipBytes(fileNameLen); | |||
| byte[] localExtraData = new byte[extraFieldLen]; | |||
| archive.readFully(localExtraData); | |||
| ze.setExtra(localExtraData); | |||
| dataOffsets.put(ze, | |||
| /*dataOffsets.put(ze, | |||
| new Long(offset + LFH_OFFSET_FOR_FILENAME_LENGTH | |||
| + 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. | |||
| * | |||
| * @param l contains the stored DOS time. | |||
| * @param zipDosTime contains the stored DOS 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(); | |||
| cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980); | |||
| 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.MINUTE, (int) (dosTime >> 5) & 0x3f); | |||
| 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 | |||
| * for this ZipFile. | |||
| @@ -29,7 +29,6 @@ public final class ZipLong implements Cloneable { | |||
| /** | |||
| * Create instance from a number. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| public ZipLong(long value) { | |||
| @@ -38,7 +37,6 @@ public final class ZipLong implements Cloneable { | |||
| /** | |||
| * Create instance from bytes. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| public ZipLong (byte[] bytes) { | |||
| @@ -47,22 +45,34 @@ public final class ZipLong implements Cloneable { | |||
| /** | |||
| * Create instance from the four bytes starting at offset. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| 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 | |||
| */ | |||
| 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]; | |||
| result[0] = (byte) ((value & 0xFF)); | |||
| 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; | |||
| } | |||
| /** | |||
| * 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. | |||
| * | |||
| @@ -27,6 +27,7 @@ import java.io.UnsupportedEncodingException; | |||
| import java.util.Date; | |||
| import java.util.Hashtable; | |||
| import java.util.Vector; | |||
| import java.util.Calendar; | |||
| import java.util.zip.CRC32; | |||
| import java.util.zip.Deflater; | |||
| import java.util.zip.ZipException; | |||
| @@ -131,14 +132,14 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| private ZipLong cdOffset = new ZipLong(0); | |||
| private long cdOffset = 0; | |||
| /** | |||
| * Length of central directory. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| private ZipLong cdLength = new ZipLong(0); | |||
| private long cdLength = 0; | |||
| /** | |||
| * Helper, a 0 as ZipShort. | |||
| @@ -297,11 +298,11 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| */ | |||
| public void finish() throws IOException { | |||
| closeEntry(); | |||
| cdOffset = new ZipLong(written); | |||
| cdOffset = written; | |||
| for (int i = 0; i < entries.size(); i++) { | |||
| writeCentralFileHeader((ZipEntry) entries.elementAt(i)); | |||
| } | |||
| cdLength = new ZipLong(written - cdOffset.getValue()); | |||
| cdLength = written - cdOffset; | |||
| writeCentralDirectoryEnd(); | |||
| offsets.clear(); | |||
| entries.removeAllElements(); | |||
| @@ -363,9 +364,9 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| long save = raf.getFilePointer(); | |||
| 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); | |||
| } | |||
| @@ -517,25 +518,25 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| protected static final ZipLong LFH_SIG = new ZipLong(0X04034B50L); | |||
| protected static final byte[] LFH_SIG = ZipLong.getBytes(0X04034B50L); | |||
| /** | |||
| * data descriptor signature | |||
| * | |||
| * @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 | |||
| * | |||
| * @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 | |||
| * | |||
| * @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. | |||
| @@ -555,9 +556,9 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| * @since 1.1 | |||
| */ | |||
| 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; | |||
| // version needed to extract | |||
| @@ -565,18 +566,18 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| if (ze.getMethod() == DEFLATED && raf == null) { | |||
| // requires version 2 as we are going to store length info | |||
| // in the data descriptor | |||
| writeOut((new ZipShort(20)).getBytes()); | |||
| writeOut(ZipShort.getBytes(20)); | |||
| // bit3 set to signal, we use a data descriptor | |||
| writeOut((new ZipShort(8)).getBytes()); | |||
| writeOut(ZipShort.getBytes(8)); | |||
| } else { | |||
| writeOut((new ZipShort(10)).getBytes()); | |||
| writeOut(ZipShort.getBytes(10)); | |||
| writeOut(ZERO); | |||
| } | |||
| written += 4; | |||
| // compression method | |||
| writeOut((new ZipShort(ze.getMethod())).getBytes()); | |||
| writeOut(ZipShort.getBytes(ze.getMethod())); | |||
| written += 2; | |||
| // last mod. time and date | |||
| @@ -592,20 +593,20 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| writeOut(LZERO); | |||
| writeOut(LZERO); | |||
| } 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; | |||
| // file name length | |||
| byte[] name = getBytes(ze.getName()); | |||
| writeOut((new ZipShort(name.length)).getBytes()); | |||
| writeOut(ZipShort.getBytes(name.length)); | |||
| written += 2; | |||
| // extra field length | |||
| byte[] extra = ze.getLocalFileDataExtra(); | |||
| writeOut((new ZipShort(extra.length)).getBytes()); | |||
| writeOut(ZipShort.getBytes(extra.length)); | |||
| written += 2; | |||
| // file name | |||
| @@ -628,10 +629,10 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| if (ze.getMethod() != DEFLATED || raf != null) { | |||
| 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; | |||
| } | |||
| @@ -641,11 +642,11 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| * @since 1.1 | |||
| */ | |||
| protected void writeCentralFileHeader(ZipEntry ze) throws IOException { | |||
| writeOut(CFH_SIG.getBytes()); | |||
| writeOut(CFH_SIG); | |||
| written += 4; | |||
| // version made by | |||
| writeOut((new ZipShort((ze.getPlatform() << 8) | 20)).getBytes()); | |||
| writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20)); | |||
| written += 2; | |||
| // version needed to extract | |||
| @@ -653,18 +654,18 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| if (ze.getMethod() == DEFLATED && raf == null) { | |||
| // requires version 2 as we are going to store length info | |||
| // in the data descriptor | |||
| writeOut((new ZipShort(20)).getBytes()); | |||
| writeOut(ZipShort.getBytes(20)); | |||
| // bit3 set to signal, we use a data descriptor | |||
| writeOut((new ZipShort(8)).getBytes()); | |||
| writeOut(ZipShort.getBytes(8)); | |||
| } else { | |||
| writeOut((new ZipShort(10)).getBytes()); | |||
| writeOut(ZipShort.getBytes(10)); | |||
| writeOut(ZERO); | |||
| } | |||
| written += 4; | |||
| // compression method | |||
| writeOut((new ZipShort(ze.getMethod())).getBytes()); | |||
| writeOut(ZipShort.getBytes(ze.getMethod())); | |||
| written += 2; | |||
| // last mod. time and date | |||
| @@ -674,19 +675,19 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| // CRC | |||
| // compressed 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; | |||
| // file name length | |||
| byte[] name = getBytes(ze.getName()); | |||
| writeOut((new ZipShort(name.length)).getBytes()); | |||
| writeOut(ZipShort.getBytes(name.length)); | |||
| written += 2; | |||
| // extra field length | |||
| byte[] extra = ze.getCentralDirectoryExtra(); | |||
| writeOut((new ZipShort(extra.length)).getBytes()); | |||
| writeOut(ZipShort.getBytes(extra.length)); | |||
| written += 2; | |||
| // file comment length | |||
| @@ -695,7 +696,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| comm = ""; | |||
| } | |||
| byte[] commentB = getBytes(comm); | |||
| writeOut((new ZipShort(commentB.length)).getBytes()); | |||
| writeOut(ZipShort.getBytes(commentB.length)); | |||
| written += 2; | |||
| // disk number start | |||
| @@ -703,15 +704,15 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| written += 2; | |||
| // internal file attributes | |||
| writeOut((new ZipShort(ze.getInternalAttributes())).getBytes()); | |||
| writeOut(ZipShort.getBytes(ze.getInternalAttributes())); | |||
| written += 2; | |||
| // external file attributes | |||
| writeOut((new ZipLong(ze.getExternalAttributes())).getBytes()); | |||
| writeOut(ZipLong.getBytes(ze.getExternalAttributes())); | |||
| written += 4; | |||
| // relative offset of LFH | |||
| writeOut(((ZipLong) offsets.get(ze)).getBytes()); | |||
| writeOut((byte[]) offsets.get(ze)); | |||
| written += 4; | |||
| // file name | |||
| @@ -733,24 +734,24 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| * @since 1.1 | |||
| */ | |||
| protected void writeCentralDirectoryEnd() throws IOException { | |||
| writeOut(EOCD_SIG.getBytes()); | |||
| writeOut(EOCD_SIG); | |||
| // disk numbers | |||
| writeOut(ZERO); | |||
| writeOut(ZERO); | |||
| // number of entries | |||
| byte[] num = (new ZipShort(entries.size())).getBytes(); | |||
| byte[] num = ZipShort.getBytes(entries.size()); | |||
| writeOut(num); | |||
| writeOut(num); | |||
| // length and location of CD | |||
| writeOut(cdLength.getBytes()); | |||
| writeOut(cdOffset.getBytes()); | |||
| writeOut(ZipLong.getBytes(cdLength)); | |||
| writeOut(ZipLong.getBytes(cdOffset)); | |||
| // ZIP file comment | |||
| byte[] data = getBytes(comment); | |||
| writeOut((new ZipShort(data.length)).getBytes()); | |||
| writeOut(ZipShort.getBytes(data.length)); | |||
| writeOut(data); | |||
| } | |||
| @@ -759,7 +760,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| * | |||
| * @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. | |||
| @@ -781,7 +782,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| Date time = new Date(t); | |||
| int year = time.getYear() + 1900; | |||
| if (year < 1980) { | |||
| return DOS_TIME_MIN.getBytes(); | |||
| return DOS_TIME_MIN; | |||
| } | |||
| int month = time.getMonth() + 1; | |||
| long value = ((year - 1980) << 25) | |||
| @@ -790,12 +791,7 @@ public class ZipOutputStream extends FilterOutputStream { | |||
| | (time.getHours() << 11) | |||
| | (time.getMinutes() << 5) | |||
| | (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. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| public ZipShort (byte[] bytes) { | |||
| @@ -47,17 +46,14 @@ public final class ZipShort implements Cloneable { | |||
| /** | |||
| * Create instance from the two bytes starting at offset. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| 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. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| public byte[] getBytes() { | |||
| @@ -69,13 +65,43 @@ public final class ZipShort implements Cloneable { | |||
| /** | |||
| * Get value as Java int. | |||
| * | |||
| * @since 1.1 | |||
| */ | |||
| public int getValue() { | |||
| 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. | |||
| * | |||