001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 */
018 package org.apache.commons.compress.archivers.zip;
019
020 import java.math.BigInteger;
021
022 /**
023 * Utility class that represents an eight byte integer with conversion
024 * rules for the big endian byte order of ZIP files.
025 * @Immutable
026 *
027 * @since Apache Commons Compress 1.2
028 */
029 public final class ZipEightByteInteger {
030
031 private static final int BYTE_MASK = 0xFF;
032
033 private static final int BYTE_1 = 1;
034 private static final int BYTE_1_MASK = 0xFF00;
035 private static final int BYTE_1_SHIFT = 8;
036
037 private static final int BYTE_2 = 2;
038 private static final int BYTE_2_MASK = 0xFF0000;
039 private static final int BYTE_2_SHIFT = 16;
040
041 private static final int BYTE_3 = 3;
042 private static final long BYTE_3_MASK = 0xFF000000L;
043 private static final int BYTE_3_SHIFT = 24;
044
045 private static final int BYTE_4 = 4;
046 private static final long BYTE_4_MASK = 0xFF00000000L;
047 private static final int BYTE_4_SHIFT = 32;
048
049 private static final int BYTE_5 = 5;
050 private static final long BYTE_5_MASK = 0xFF0000000000L;
051 private static final int BYTE_5_SHIFT = 40;
052
053 private static final int BYTE_6 = 6;
054 private static final long BYTE_6_MASK = 0xFF000000000000L;
055 private static final int BYTE_6_SHIFT = 48;
056
057 private static final int BYTE_7 = 7;
058 private static final long BYTE_7_MASK = 0x7F00000000000000L;
059 private static final int BYTE_7_SHIFT = 56;
060
061 private static final int LEFTMOST_BIT_SHIFT = 63;
062 private static final byte LEFTMOST_BIT = (byte) 0x80;
063
064 private final BigInteger value;
065
066 /**
067 * Create instance from a number.
068 * @param value the long to store as a ZipEightByteInteger
069 */
070 public ZipEightByteInteger(long value) {
071 this(BigInteger.valueOf(value));
072 }
073
074 /**
075 * Create instance from a number.
076 * @param value the BigInteger to store as a ZipEightByteInteger
077 */
078 public ZipEightByteInteger(BigInteger value) {
079 this.value = value;
080 }
081
082 /**
083 * Create instance from bytes.
084 * @param bytes the bytes to store as a ZipEightByteInteger
085 */
086 public ZipEightByteInteger (byte[] bytes) {
087 this(bytes, 0);
088 }
089
090 /**
091 * Create instance from the eight bytes starting at offset.
092 * @param bytes the bytes to store as a ZipEightByteInteger
093 * @param offset the offset to start
094 */
095 public ZipEightByteInteger (byte[] bytes, int offset) {
096 value = ZipEightByteInteger.getValue(bytes, offset);
097 }
098
099 /**
100 * Get value as eight bytes in big endian byte order.
101 * @return value as eight bytes in big endian order
102 */
103 public byte[] getBytes() {
104 return ZipEightByteInteger.getBytes(value);
105 }
106
107 /**
108 * Get value as Java long.
109 * @return value as a long
110 */
111 public long getLongValue() {
112 return value.longValue();
113 }
114
115 /**
116 * Get value as Java long.
117 * @return value as a long
118 */
119 public BigInteger getValue() {
120 return value;
121 }
122
123 /**
124 * Get value as eight bytes in big endian byte order.
125 * @param value the value to convert
126 * @return value as eight bytes in big endian byte order
127 */
128 public static byte[] getBytes(long value) {
129 return getBytes(BigInteger.valueOf(value));
130 }
131
132 /**
133 * Get value as eight bytes in big endian byte order.
134 * @param value the value to convert
135 * @return value as eight bytes in big endian byte order
136 */
137 public static byte[] getBytes(BigInteger value) {
138 byte[] result = new byte[8];
139 long val = value.longValue();
140 result[0] = (byte) ((val & BYTE_MASK));
141 result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT);
142 result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT);
143 result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT);
144 result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT);
145 result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT);
146 result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT);
147 result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT);
148 if (value.testBit(LEFTMOST_BIT_SHIFT)) {
149 result[BYTE_7] |= LEFTMOST_BIT;
150 }
151 return result;
152 }
153
154 /**
155 * Helper method to get the value as a Java long from eight bytes
156 * starting at given array offset
157 * @param bytes the array of bytes
158 * @param offset the offset to start
159 * @return the corresponding Java long value
160 */
161 public static long getLongValue(byte[] bytes, int offset) {
162 return getValue(bytes, offset).longValue();
163 }
164
165 /**
166 * Helper method to get the value as a Java BigInteger from eight
167 * bytes starting at given array offset
168 * @param bytes the array of bytes
169 * @param offset the offset to start
170 * @return the corresponding Java BigInteger value
171 */
172 public static BigInteger getValue(byte[] bytes, int offset) {
173 long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK;
174 value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK;
175 value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK;
176 value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK;
177 value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
178 value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
179 value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
180 value += ((long) bytes[offset] & BYTE_MASK);
181 BigInteger val = BigInteger.valueOf(value);
182 return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT
183 ? val.setBit(LEFTMOST_BIT_SHIFT) : val;
184 }
185
186 /**
187 * Helper method to get the value as a Java long from an eight-byte array
188 * @param bytes the array of bytes
189 * @return the corresponding Java long value
190 */
191 public static long getLongValue(byte[] bytes) {
192 return getLongValue(bytes, 0);
193 }
194
195 /**
196 * Helper method to get the value as a Java long from an eight-byte array
197 * @param bytes the array of bytes
198 * @return the corresponding Java BigInteger value
199 */
200 public static BigInteger getValue(byte[] bytes) {
201 return getValue(bytes, 0);
202 }
203
204 /**
205 * Override to make two instances with same value equal.
206 * @param o an object to compare
207 * @return true if the objects are equal
208 */
209 public boolean equals(Object o) {
210 if (o == null || !(o instanceof ZipEightByteInteger)) {
211 return false;
212 }
213 return value.equals(((ZipEightByteInteger) o).getValue());
214 }
215
216 /**
217 * Override to make two instances with same value equal.
218 * @return the hashCode of the value stored in the ZipEightByteInteger
219 */
220 public int hashCode() {
221 return value.hashCode();
222 }
223
224 public String toString() {
225 return "ZipEightByteInteger value: " + value;
226 }
227 }