Author: bodewig Date: Thu Jul 21 08:37:01 2011 New Revision: 1149070 URL: http://svn.apache.org/viewvc?rev=1149070&view=rev Log: first piece of infrastructure for ZIP64 support, deal with numbers represented as eight bytes in big-endian order. COMPRESS-36
Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java - copied, changed from r1149049, commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipEightByteIntegerTest.java - copied, changed from r1149049, commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipLongTest.java Copied: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java (from r1149049, commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java) URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java?p2=commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java&p1=commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java&r1=1149049&r2=1149070&rev=1149070&view=diff ============================================================================== --- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipLong.java (original) +++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java Thu Jul 21 08:37:01 2011 @@ -17,15 +17,15 @@ */ package org.apache.commons.compress.archivers.zip; +import java.math.BigInteger; + /** - * Utility class that represents a four byte integer with conversion + * Utility class that represents an eight byte integer with conversion * rules for the big endian byte order of ZIP files. * @Immutable */ -public final class ZipLong implements Cloneable { +public final class ZipEightByteInteger { - private static final int WORD = 4; - //private static final int BYTE_BIT_SIZE = 8; private static final int BYTE_MASK = 0xFF; private static final int BYTE_1 = 1; @@ -40,95 +40,162 @@ public final class ZipLong implements Cl private static final long BYTE_3_MASK = 0xFF000000L; private static final int BYTE_3_SHIFT = 24; - private final long value; + private static final int BYTE_4 = 4; + private static final long BYTE_4_MASK = 0xFF00000000L; + private static final int BYTE_4_SHIFT = 32; + + private static final int BYTE_5 = 5; + private static final long BYTE_5_MASK = 0xFF0000000000L; + private static final int BYTE_5_SHIFT = 40; + + private static final int BYTE_6 = 6; + private static final long BYTE_6_MASK = 0xFF000000000000L; + private static final int BYTE_6_SHIFT = 48; + + private static final int BYTE_7 = 7; + private static final long BYTE_7_MASK = 0x7F00000000000000L; + private static final int BYTE_7_SHIFT = 56; - /** Central File Header Signature */ - public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L); + private static final int LEFTMOST_BIT_SHIFT = 63; + private static final byte LEFTMOST_BIT = (byte) 0x80; - /** Local File Header Signature */ - public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L); + private final BigInteger value; /** - * Data Descriptor signature - * @since Apache Commons Compress 1.1 + * Create instance from a number. + * @param value the long to store as a ZipEightByteInteger */ - public static final ZipLong DD_SIG = new ZipLong(0X08074B50L); + public ZipEightByteInteger(long value) { + this(BigInteger.valueOf(value)); + } /** * Create instance from a number. - * @param value the long to store as a ZipLong + * @param value the BigInteger to store as a ZipEightByteInteger */ - public ZipLong(long value) { + public ZipEightByteInteger(BigInteger value) { this.value = value; } /** * Create instance from bytes. - * @param bytes the bytes to store as a ZipLong + * @param bytes the bytes to store as a ZipEightByteInteger */ - public ZipLong (byte[] bytes) { + public ZipEightByteInteger (byte[] bytes) { this(bytes, 0); } /** - * Create instance from the four bytes starting at offset. - * @param bytes the bytes to store as a ZipLong + * Create instance from the eight bytes starting at offset. + * @param bytes the bytes to store as a ZipEightByteInteger * @param offset the offset to start */ - public ZipLong (byte[] bytes, int offset) { - value = ZipLong.getValue(bytes, offset); + public ZipEightByteInteger (byte[] bytes, int offset) { + value = ZipEightByteInteger.getValue(bytes, offset); } /** - * Get value as four bytes in big endian byte order. - * @return value as four bytes in big endian order + * Get value as eight bytes in big endian byte order. + * @return value as eight bytes in big endian order */ public byte[] getBytes() { - return ZipLong.getBytes(value); + return ZipEightByteInteger.getBytes(value); } /** * Get value as Java long. * @return value as a long */ - public long getValue() { + public long getLongValue() { + return value.longValue(); + } + + /** + * Get value as Java long. + * @return value as a long + */ + public BigInteger getValue() { return value; } /** - * Get value as four bytes in big endian byte order. + * Get value as eight bytes in big endian byte order. * @param value the value to convert - * @return value as four bytes in big endian byte order + * @return value as eight bytes in big endian byte order */ public static byte[] getBytes(long value) { - byte[] result = new byte[WORD]; - result[0] = (byte) ((value & BYTE_MASK)); - result[BYTE_1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT); - result[BYTE_2] = (byte) ((value & BYTE_2_MASK) >> BYTE_2_SHIFT); - result[BYTE_3] = (byte) ((value & BYTE_3_MASK) >> BYTE_3_SHIFT); + return getBytes(BigInteger.valueOf(value)); + } + + /** + * Get value as eight bytes in big endian byte order. + * @param value the value to convert + * @return value as eight bytes in big endian byte order + */ + public static byte[] getBytes(BigInteger value) { + byte[] result = new byte[8]; + long val = value.longValue(); + result[0] = (byte) ((val & BYTE_MASK)); + result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT); + result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT); + result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT); + result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT); + result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT); + result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT); + result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT); + if (value.testBit(LEFTMOST_BIT_SHIFT)) { + result[BYTE_7] |= LEFTMOST_BIT; + } return result; } /** - * Helper method to get the value as a Java long from four bytes starting at given array offset + * Helper method to get the value as a Java long from eight bytes + * starting at given array offset * @param bytes the array of bytes * @param offset the offset to start - * @return the correspondanding Java long value + * @return the corresponding Java long value */ - public static long getValue(byte[] bytes, int offset) { - long value = (bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK; - value += (bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK; - value += (bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK; - value += (bytes[offset] & BYTE_MASK); - return value; + public static long getLongValue(byte[] bytes, int offset) { + return getValue(bytes, offset).longValue(); + } + + /** + * Helper method to get the value as a Java BigInteger from eight + * bytes starting at given array offset + * @param bytes the array of bytes + * @param offset the offset to start + * @return the corresponding Java BigInteger value + */ + public static BigInteger getValue(byte[] bytes, int offset) { + long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK; + value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK; + value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK; + value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK; + value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK; + value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK; + value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK; + value += ((long) bytes[offset] & BYTE_MASK); + BigInteger val = BigInteger.valueOf(value); + return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT + ? val.setBit(LEFTMOST_BIT_SHIFT) : val; } /** - * Helper method to get the value as a Java long from a four-byte array + * Helper method to get the value as a Java long from an eight-byte array * @param bytes the array of bytes - * @return the correspondanding Java long value + * @return the corresponding Java long value */ - public static long getValue(byte[] bytes) { + public static long getLongValue(byte[] bytes) { + return getLongValue(bytes, 0); + } + + /** + * Helper method to get the value as a Java long from an eight-byte array + * @param bytes the array of bytes + * @return the corresponding Java BigInteger value + */ + public static BigInteger getValue(byte[] bytes) { return getValue(bytes, 0); } @@ -138,26 +205,17 @@ public final class ZipLong implements Cl * @return true if the objects are equal */ public boolean equals(Object o) { - if (o == null || !(o instanceof ZipLong)) { + if (o == null || !(o instanceof ZipEightByteInteger)) { return false; } - return value == ((ZipLong) o).getValue(); + return value.equals(((ZipEightByteInteger) o).getValue()); } /** * Override to make two instances with same value equal. - * @return the value stored in the ZipLong + * @return the hashCode of the value stored in the ZipEightByteInteger */ public int hashCode() { - return (int) value; - } - - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException cnfe) { - // impossible - throw new RuntimeException(cnfe); - } + return value.hashCode(); } } Copied: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipEightByteIntegerTest.java (from r1149049, commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipLongTest.java) URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipEightByteIntegerTest.java?p2=commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipEightByteIntegerTest.java&p1=commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipLongTest.java&r1=1149049&r2=1149070&rev=1149070&view=diff ============================================================================== --- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipLongTest.java (original) +++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipEightByteIntegerTest.java Thu Jul 21 08:37:01 2011 @@ -18,47 +18,82 @@ package org.apache.commons.compress.archivers.zip; +import java.math.BigInteger; import junit.framework.TestCase; /** - * JUnit 3 testcases for org.apache.commons.compress.archivers.zip.ZipLong. + * JUnit 3 testcases for org.apache.commons.compress.archivers.zip.ZipEightByteInteger. * */ -public class ZipLongTest extends TestCase { +public class ZipEightByteIntegerTest extends TestCase { - public ZipLongTest(String name) { + public ZipEightByteIntegerTest(String name) { super(name); } /** * Test conversion to bytes. */ - public void testToBytes() { - ZipLong zl = new ZipLong(0x12345678); + public void testLongToBytes() { + ZipEightByteInteger zl = new ZipEightByteInteger(0xAB12345678l); byte[] result = zl.getBytes(); - assertEquals("length getBytes", 4, result.length); + assertEquals("length getBytes", 8, result.length); assertEquals("first byte getBytes", 0x78, result[0]); assertEquals("second byte getBytes", 0x56, result[1]); assertEquals("third byte getBytes", 0x34, result[2]); assertEquals("fourth byte getBytes", 0x12, result[3]); + assertEquals("fifth byte getBytes", (byte) 0xAB, result[4]); + assertEquals("sixth byte getBytes", 0, result[5]); + assertEquals("seventh byte getBytes", 0, result[6]); + assertEquals("eighth byte getBytes", 0, result[7]); } /** * Test conversion from bytes. */ - public void testFromBytes() { - byte[] val = new byte[] {0x78, 0x56, 0x34, 0x12}; - ZipLong zl = new ZipLong(val); - assertEquals("value from bytes", 0x12345678, zl.getValue()); + public void testLongFromBytes() { + byte[] val = new byte[] {0x78, 0x56, 0x34, 0x12, (byte) 0xAB, 0x00, 0x00, 0x00}; + ZipEightByteInteger zl = new ZipEightByteInteger(val); + assertEquals("longValue from bytes", 0xAB12345678l, zl.getLongValue()); + } + + /** + * Test conversion to bytes. + */ + public void testBIToBytes() { + ZipEightByteInteger zl = + new ZipEightByteInteger(BigInteger.valueOf(Long.MAX_VALUE) + .shiftLeft(1)); + byte[] result = zl.getBytes(); + assertEquals("length getBytes", 8, result.length); + assertEquals("first byte getBytes", (byte) 0xFE, result[0]); + assertEquals("second byte getBytes", (byte) 0xFF, result[1]); + assertEquals("third byte getBytes", (byte) 0xFF, result[2]); + assertEquals("fourth byte getBytes", (byte) 0xFF, result[3]); + assertEquals("fifth byte getBytes", (byte) 0xFF, result[4]); + assertEquals("sixth byte getBytes", (byte) 0xFF, result[5]); + assertEquals("seventh byte getBytes", (byte) 0xFF, result[6]); + assertEquals("eighth byte getBytes", (byte) 0xFF, result[7]); + } + + /** + * Test conversion from bytes. + */ + public void testBIFromBytes() { + byte[] val = new byte[] {(byte) 0xFE, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; + ZipEightByteInteger zl = new ZipEightByteInteger(val); + assertEquals("value from bytes", + BigInteger.valueOf(Long.MAX_VALUE).shiftLeft(1), + zl.getValue()); } /** * Test the contract of the equals method. */ public void testEquals() { - ZipLong zl = new ZipLong(0x12345678); - ZipLong zl2 = new ZipLong(0x12345678); - ZipLong zl3 = new ZipLong(0x87654321); + ZipEightByteInteger zl = new ZipEightByteInteger(0x12345678); + ZipEightByteInteger zl2 = new ZipEightByteInteger(0x12345678); + ZipEightByteInteger zl3 = new ZipEightByteInteger(0x87654321); assertTrue("reflexive", zl.equals(zl)); @@ -68,22 +103,15 @@ public class ZipLongTest extends TestCas assertTrue("symmetric", zl2.equals(zl)); assertTrue("null handling", !zl.equals(null)); - assertTrue("non ZipLong handling", !zl.equals(new Integer(0x1234))); + assertTrue("non ZipEightByteInteger handling", !zl.equals(new Integer(0x1234))); } /** * Test sign handling. */ public void testSign() { - ZipLong zl = new ZipLong(new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF}); - assertEquals(0x00000000FFFFFFFFl, zl.getValue()); - } - - public void testClone() { - ZipLong s1 = new ZipLong(42); - ZipLong s2 = (ZipLong) s1.clone(); - assertNotSame(s1, s2); - assertEquals(s1, s2); - assertEquals(s1.getValue(), s2.getValue()); + ZipEightByteInteger zl = new ZipEightByteInteger(new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF}); + assertEquals(BigInteger.valueOf(Long.MAX_VALUE).shiftLeft(1).setBit(0), + zl.getValue()); } }