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 import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;
023
024 /**
025 * Utility class that represents an eight byte integer with conversion
026 * rules for the big endian byte order of ZIP files.
027 * @Immutable
028 *
029 * @since 1.2
030 */
031 public final class ZipEightByteInteger {
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 public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0);
067
068 /**
069 * Create instance from a number.
070 * @param value the long to store as a ZipEightByteInteger
071 */
072 public ZipEightByteInteger(long value) {
073 this(BigInteger.valueOf(value));
074 }
075
076 /**
077 * Create instance from a number.
078 * @param value the BigInteger to store as a ZipEightByteInteger
079 */
080 public ZipEightByteInteger(BigInteger value) {
081 this.value = value;
082 }
083
084 /**
085 * Create instance from bytes.
086 * @param bytes the bytes to store as a ZipEightByteInteger
087 */
088 public ZipEightByteInteger (byte[] bytes) {
089 this(bytes, 0);
090 }
091
092 /**
093 * Create instance from the eight bytes starting at offset.
094 * @param bytes the bytes to store as a ZipEightByteInteger
095 * @param offset the offset to start
096 */
097 public ZipEightByteInteger (byte[] bytes, int offset) {
098 value = ZipEightByteInteger.getValue(bytes, offset);
099 }
100
101 /**
102 * Get value as eight bytes in big endian byte order.
103 * @return value as eight bytes in big endian order
104 */
105 public byte[] getBytes() {
106 return ZipEightByteInteger.getBytes(value);
107 }
108
109 /**
110 * Get value as Java long.
111 * @return value as a long
112 */
113 public long getLongValue() {
114 return value.longValue();
115 }
116
117 /**
118 * Get value as Java long.
119 * @return value as a long
120 */
121 public BigInteger getValue() {
122 return value;
123 }
124
125 /**
126 * Get value as eight bytes in big endian byte order.
127 * @param value the value to convert
128 * @return value as eight bytes in big endian byte order
129 */
130 public static byte[] getBytes(long value) {
131 return getBytes(BigInteger.valueOf(value));
132 }
133
134 /**
135 * Get value as eight bytes in big endian byte order.
136 * @param value the value to convert
137 * @return value as eight bytes in big endian byte order
138 */
139 public static byte[] getBytes(BigInteger value) {
140 byte[] result = new byte[8];
141 long val = value.longValue();
142 result[0] = (byte) ((val & BYTE_MASK));
143 result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT);
144 result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT);
145 result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT);
146 result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT);
147 result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT);
148 result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT);
149 result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT);
150 if (value.testBit(LEFTMOST_BIT_SHIFT)) {
151 result[BYTE_7] |= LEFTMOST_BIT;
152 }
153 return result;
154 }
155
156 /**
157 * Helper method to get the value as a Java long from eight bytes
158 * starting at given array offset
159 * @param bytes the array of bytes
160 * @param offset the offset to start
161 * @return the corresponding Java long value
162 */
163 public static long getLongValue(byte[] bytes, int offset) {
164 return getValue(bytes, offset).longValue();
165 }
166
167 /**
168 * Helper method to get the value as a Java BigInteger from eight
169 * bytes starting at given array offset
170 * @param bytes the array of bytes
171 * @param offset the offset to start
172 * @return the corresponding Java BigInteger value
173 */
174 public static BigInteger getValue(byte[] bytes, int offset) {
175 long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK;
176 value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK;
177 value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK;
178 value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK;
179 value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
180 value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
181 value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
182 value += ((long) bytes[offset] & BYTE_MASK);
183 BigInteger val = BigInteger.valueOf(value);
184 return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT
185 ? val.setBit(LEFTMOST_BIT_SHIFT) : val;
186 }
187
188 /**
189 * Helper method to get the value as a Java long from an eight-byte array
190 * @param bytes the array of bytes
191 * @return the corresponding Java long value
192 */
193 public static long getLongValue(byte[] bytes) {
194 return getLongValue(bytes, 0);
195 }
196
197 /**
198 * Helper method to get the value as a Java long from an eight-byte array
199 * @param bytes the array of bytes
200 * @return the corresponding Java BigInteger value
201 */
202 public static BigInteger getValue(byte[] bytes) {
203 return getValue(bytes, 0);
204 }
205
206 /**
207 * Override to make two instances with same value equal.
208 * @param o an object to compare
209 * @return true if the objects are equal
210 */
211 @Override
212 public boolean equals(Object o) {
213 if (o == null || !(o instanceof ZipEightByteInteger)) {
214 return false;
215 }
216 return value.equals(((ZipEightByteInteger) o).getValue());
217 }
218
219 /**
220 * Override to make two instances with same value equal.
221 * @return the hashCode of the value stored in the ZipEightByteInteger
222 */
223 @Override
224 public int hashCode() {
225 return value.hashCode();
226 }
227
228 @Override
229 public String toString() {
230 return "ZipEightByteInteger value: " + value;
231 }
232 }