View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.archivers.zip;
20  
21  import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
22  
23  import java.io.Serializable;
24  
25  import org.apache.commons.compress.utils.ByteUtils;
26  
27  /**
28   * Utility class that represents a four byte integer with conversion rules for the little-endian byte order of ZIP files.
29   *
30   * @Immutable
31   */
32  public final class ZipLong implements Cloneable, Serializable {
33  
34      private static final long serialVersionUID = 1L;
35  
36      /** Central File Header Signature */
37      public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L);
38  
39      /** Local File Header Signature */
40      public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L);
41  
42      /**
43       * Data Descriptor signature.
44       *
45       * <p>
46       * Actually, PKWARE uses this as marker for split/spanned archives and other archivers have started to use it as Data Descriptor signature (as well).
47       * </p>
48       *
49       * @since 1.1
50       */
51      public static final ZipLong DD_SIG = new ZipLong(0X08074B50L);
52  
53      /**
54       * Value stored in size and similar fields if ZIP64 extensions are used.
55       *
56       * @since 1.3
57       */
58      static final ZipLong ZIP64_MAGIC = new ZipLong(ZipConstants.ZIP64_MAGIC);
59  
60      /**
61       * Marks ZIP archives that were supposed to be split or spanned but only needed a single segment in then end (so are actually neither split nor spanned).
62       *
63       * <p>
64       * This is the "PK00" prefix found in some archives.
65       * </p>
66       *
67       * @since 1.5
68       */
69      public static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER = new ZipLong(0X30304B50L);
70  
71      /**
72       * Archive extra data record signature.
73       *
74       * @since 1.5
75       */
76      public static final ZipLong AED_SIG = new ZipLong(0X08064B50L);
77  
78      /**
79       * Gets value as four bytes in big-endian byte order.
80       *
81       * @param value the value to convert
82       * @return value as four bytes in big-endian byte order
83       */
84      public static byte[] getBytes(final long value) {
85          final byte[] result = new byte[WORD];
86          putLong(value, result, 0);
87          return result;
88      }
89  
90      /**
91       * Helper method to get the value as a Java long from a four-byte array
92       *
93       * @param bytes the array of bytes
94       * @return the corresponding Java long value
95       */
96      public static long getValue(final byte[] bytes) {
97          return getValue(bytes, 0);
98      }
99  
100     /**
101      * Helper method to get the value as a Java long from four bytes starting at given array offset
102      *
103      * @param bytes  the array of bytes
104      * @param offset the offset to start
105      * @return the corresponding Java long value
106      */
107     public static long getValue(final byte[] bytes, final int offset) {
108         return ByteUtils.fromLittleEndian(bytes, offset, 4);
109     }
110 
111     /**
112      * Puts a long value in a buffer as four bytes in little-endian byte order.
113      *
114      * @param value  the Java long to convert to bytes
115      * @param buf    the output buffer
116      * @param offset The offset within the output buffer of the first byte to be written. must be non-negative and no larger than {@code buf.length-4}
117      */
118     public static void putLong(final long value, final byte[] buf, final int offset) {
119         ByteUtils.toLittleEndian(buf, value, offset, 4);
120     }
121 
122     private final long value;
123 
124     /**
125      * Constructs a new instance from bytes.
126      *
127      * @param bytes the bytes to store as a ZipLong
128      */
129     public ZipLong(final byte[] bytes) {
130         this(bytes, 0);
131     }
132 
133     /**
134      * Creates instance from the four bytes starting at offset.
135      *
136      * @param bytes  the bytes to store as a ZipLong
137      * @param offset the offset to start
138      */
139     public ZipLong(final byte[] bytes, final int offset) {
140         value = getValue(bytes, offset);
141     }
142 
143     /**
144      * create instance from a Java int.
145      *
146      * @param value the int to store as a ZipLong
147      * @since 1.15
148      */
149     public ZipLong(final int value) {
150         this.value = value;
151     }
152 
153     /**
154      * Creates instance from a number.
155      *
156      * @param value the long to store as a ZipLong
157      */
158     public ZipLong(final long value) {
159         this.value = value;
160     }
161 
162     @Override
163     public Object clone() {
164         try {
165             return super.clone();
166         } catch (final CloneNotSupportedException cnfe) {
167             // impossible
168             throw new UnsupportedOperationException(cnfe); // NOSONAR
169         }
170     }
171 
172     /**
173      * Override to make two instances with same value equal.
174      *
175      * @param o an object to compare
176      * @return true if the objects are equal
177      */
178     @Override
179     public boolean equals(final Object o) {
180         if (!(o instanceof ZipLong)) {
181             return false;
182         }
183         return value == ((ZipLong) o).getValue();
184     }
185 
186     /**
187      * Gets value as four bytes in big-endian byte order.
188      *
189      * @return value as four bytes in big-endian order
190      */
191     public byte[] getBytes() {
192         return getBytes(value);
193     }
194 
195     /**
196      * Gets value as a (signed) Java int
197      *
198      * @return value as int
199      * @since 1.15
200      */
201     public int getIntValue() {
202         return (int) value;
203     }
204 
205     /**
206      * Gets value as Java long.
207      *
208      * @return value as a long
209      */
210     public long getValue() {
211         return value;
212     }
213 
214     /**
215      * Override to make two instances with same value equal.
216      *
217      * @return the value stored in the ZipLong
218      */
219     @Override
220     public int hashCode() {
221         return (int) value;
222     }
223 
224     /**
225      * Puts this long value in a buffer as four bytes in little-endian byte order.
226      *
227      * @param buf    the output buffer
228      * @param offset The offset within the output buffer of the first byte to be written. must be non-negative and no larger than {@code buf.length-4}
229      */
230     public void putLong(final byte[] buf, final int offset) {
231         putLong(value, buf, offset);
232     }
233 
234     @Override
235     public String toString() {
236         return "ZipLong value: " + value;
237     }
238 }