View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.commons.compress.archivers.zip;
18  
19  import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;
20  
21  import java.io.Serializable;
22  import java.math.BigInteger;
23  
24  /**
25   * Utility class that represents an eight byte integer with conversion rules for the little-endian byte order of ZIP files.
26   *
27   * @Immutable
28   *
29   * @since 1.2
30   */
31  public final class ZipEightByteInteger implements Serializable {
32      private static final long serialVersionUID = 1L;
33  
34      private static final int BYTE_1 = 1;
35      private static final int BYTE_1_MASK = 0xFF00;
36      private static final int BYTE_1_SHIFT = 8;
37  
38      private static final int BYTE_2 = 2;
39      private static final int BYTE_2_MASK = 0xFF0000;
40      private static final int BYTE_2_SHIFT = 16;
41  
42      private static final int BYTE_3 = 3;
43      private static final long BYTE_3_MASK = 0xFF000000L;
44      private static final int BYTE_3_SHIFT = 24;
45  
46      private static final int BYTE_4 = 4;
47      private static final long BYTE_4_MASK = 0xFF00000000L;
48      private static final int BYTE_4_SHIFT = 32;
49  
50      private static final int BYTE_5 = 5;
51      private static final long BYTE_5_MASK = 0xFF0000000000L;
52      private static final int BYTE_5_SHIFT = 40;
53  
54      private static final int BYTE_6 = 6;
55      private static final long BYTE_6_MASK = 0xFF000000000000L;
56      private static final int BYTE_6_SHIFT = 48;
57  
58      private static final int BYTE_7 = 7;
59      private static final long BYTE_7_MASK = 0x7F00000000000000L;
60      private static final int BYTE_7_SHIFT = 56;
61  
62      private static final int LEFTMOST_BIT_SHIFT = 63;
63      private static final byte LEFTMOST_BIT = (byte) 0x80;
64  
65      public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0);
66  
67      /**
68       * Gets value as eight bytes in big-endian byte order.
69       *
70       * @param value the value to convert
71       * @return value as eight bytes in big-endian byte order
72       */
73      public static byte[] getBytes(final BigInteger value) {
74          final byte[] result = new byte[8];
75          final long val = value.longValue();
76          result[0] = (byte) (val & BYTE_MASK);
77          result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT);
78          result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT);
79          result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT);
80          result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT);
81          result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT);
82          result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT);
83          result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT);
84          if (value.testBit(LEFTMOST_BIT_SHIFT)) {
85              result[BYTE_7] |= LEFTMOST_BIT;
86          }
87          return result;
88      }
89  
90      /**
91       * Gets value as eight bytes in big-endian byte order.
92       *
93       * @param value the value to convert
94       * @return value as eight bytes in big-endian byte order
95       */
96      public static byte[] getBytes(final long value) {
97          return getBytes(BigInteger.valueOf(value));
98      }
99  
100     /**
101      * Helper method to get the value as a Java long from an eight-byte array
102      *
103      * @param bytes the array of bytes
104      * @return the corresponding Java long value
105      */
106     public static long getLongValue(final byte[] bytes) {
107         return getLongValue(bytes, 0);
108     }
109 
110     /**
111      * Helper method to get the value as a Java long from eight bytes starting at given array offset
112      *
113      * @param bytes  the array of bytes
114      * @param offset the offset to start
115      * @return the corresponding Java long value
116      */
117     public static long getLongValue(final byte[] bytes, final int offset) {
118         return getValue(bytes, offset).longValue();
119     }
120 
121     /**
122      * Helper method to get the value as a Java long from an eight-byte array
123      *
124      * @param bytes the array of bytes
125      * @return the corresponding Java BigInteger value
126      */
127     public static BigInteger getValue(final byte[] bytes) {
128         return getValue(bytes, 0);
129     }
130 
131     /**
132      * Helper method to get the value as a Java BigInteger from eight bytes starting at given array offset
133      *
134      * @param bytes  the array of bytes
135      * @param offset the offset to start
136      * @return the corresponding Java BigInteger value
137      */
138     public static BigInteger getValue(final byte[] bytes, final int offset) {
139         long value = (long) bytes[offset + BYTE_7] << BYTE_7_SHIFT & BYTE_7_MASK;
140         value += (long) bytes[offset + BYTE_6] << BYTE_6_SHIFT & BYTE_6_MASK;
141         value += (long) bytes[offset + BYTE_5] << BYTE_5_SHIFT & BYTE_5_MASK;
142         value += (long) bytes[offset + BYTE_4] << BYTE_4_SHIFT & BYTE_4_MASK;
143         value += (long) bytes[offset + BYTE_3] << BYTE_3_SHIFT & BYTE_3_MASK;
144         value += (long) bytes[offset + BYTE_2] << BYTE_2_SHIFT & BYTE_2_MASK;
145         value += (long) bytes[offset + BYTE_1] << BYTE_1_SHIFT & BYTE_1_MASK;
146         value += (long) bytes[offset] & BYTE_MASK;
147         final BigInteger val = BigInteger.valueOf(value);
148         return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT ? val.setBit(LEFTMOST_BIT_SHIFT) : val;
149     }
150 
151     private final BigInteger value;
152 
153     /**
154      * Constructs a new instance from a number.
155      *
156      * @param value the BigInteger to store as a ZipEightByteInteger
157      */
158     public ZipEightByteInteger(final BigInteger value) {
159         this.value = value;
160     }
161 
162     /**
163      * Constructs a new instance from bytes.
164      *
165      * @param bytes the bytes to store as a ZipEightByteInteger
166      */
167     public ZipEightByteInteger(final byte[] bytes) {
168         this(bytes, 0);
169     }
170 
171     /**
172      * Constructs a new instance from the eight bytes starting at offset.
173      *
174      * @param bytes  the bytes to store as a ZipEightByteInteger
175      * @param offset the offset to start
176      */
177     public ZipEightByteInteger(final byte[] bytes, final int offset) {
178         value = getValue(bytes, offset);
179     }
180 
181     /**
182      * Constructs a new instance from a number.
183      *
184      * @param value the long to store as a ZipEightByteInteger
185      */
186     public ZipEightByteInteger(final long value) {
187         this(BigInteger.valueOf(value));
188     }
189 
190     /**
191      * Override to make two instances with same value equal.
192      *
193      * @param o an object to compare
194      * @return true if the objects are equal
195      */
196     @Override
197     public boolean equals(final Object o) {
198         if (!(o instanceof ZipEightByteInteger)) {
199             return false;
200         }
201         return value.equals(((ZipEightByteInteger) o).getValue());
202     }
203 
204     /**
205      * Gets value as eight bytes in big-endian byte order.
206      *
207      * @return value as eight bytes in big-endian order
208      */
209     public byte[] getBytes() {
210         return getBytes(value);
211     }
212 
213     /**
214      * Gets value as Java long.
215      *
216      * @return value as a long
217      */
218     public long getLongValue() {
219         return value.longValue();
220     }
221 
222     /**
223      * Gets value as Java BigInteger.
224      *
225      * @return value as a BigInteger
226      */
227     public BigInteger getValue() {
228         return value;
229     }
230 
231     /**
232      * Override to make two instances with same value equal.
233      *
234      * @return the hash code of the value stored in the ZipEightByteInteger
235      */
236     @Override
237     public int hashCode() {
238         return value.hashCode();
239     }
240 
241     @Override
242     public String toString() {
243         return "ZipEightByteInteger value: " + value;
244     }
245 }