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.WORD;
20
21 import java.io.Serializable;
22
23 import org.apache.commons.compress.utils.ByteUtils;
24
25 /**
26  * Utility class that represents a four byte integer with conversion rules for the little-endian byte order of ZIP files.
27  *
28  * @Immutable
29  */

30 public final class ZipLong implements Cloneable, Serializable {
31     private static final long serialVersionUID = 1L;
32
33     /** Central File Header Signature */
34     public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L);
35
36     /** Local File Header Signature */
37     public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L);
38
39     /**
40      * Data Descriptor signature.
41      *
42      * <p>
43      * Actually, PKWARE uses this as marker for split/spanned archives and other archivers have started to use it as Data Descriptor signature (as well).
44      * </p>
45      *
46      * @since 1.1
47      */

48     public static final ZipLong DD_SIG = new ZipLong(0X08074B50L);
49
50     /**
51      * Value stored in size and similar fields if ZIP64 extensions are used.
52      *
53      * @since 1.3
54      */

55     static final ZipLong ZIP64_MAGIC = new ZipLong(ZipConstants.ZIP64_MAGIC);
56
57     /**
58      * 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).
59      *
60      * <p>
61      * This is the "PK00" prefix found in some archives.
62      * </p>
63      *
64      * @since 1.5
65      */

66     public static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER = new ZipLong(0X30304B50L);
67
68     /**
69      * Archive extra data record signature.
70      *
71      * @since 1.5
72      */

73     public static final ZipLong AED_SIG = new ZipLong(0X08064B50L);
74
75     /**
76      * Gets value as four bytes in big-endian byte order.
77      *
78      * @param value the value to convert
79      * @return value as four bytes in big-endian byte order
80      */

81     public static byte[] getBytes(final long value) {
82         final byte[] result = new byte[WORD];
83         putLong(value, result, 0);
84         return result;
85     }
86
87     /**
88      * Helper method to get the value as a Java long from a four-byte array
89      *
90      * @param bytes the array of bytes
91      * @return the corresponding Java long value
92      */

93     public static long getValue(final byte[] bytes) {
94         return getValue(bytes, 0);
95     }
96
97     /**
98      * Helper method to get the value as a Java long from four bytes starting at given array offset
99      *
100      * @param bytes  the array of bytes
101      * @param offset the offset to start
102      * @return the corresponding Java long value
103      */

104     public static long getValue(final byte[] bytes, final int offset) {
105         return ByteUtils.fromLittleEndian(bytes, offset, 4);
106     }
107
108     /**
109      * put the value as four bytes in big-endian byte order.
110      *
111      * @param value  the Java long to convert to bytes
112      * @param buf    the output buffer
113      * @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}
114      */

115
116     public static void putLong(final long value, final byte[] buf, final int offset) {
117         ByteUtils.toLittleEndian(buf, value, offset, 4);
118     }
119
120     private final long value;
121
122     /**
123      * Constructs a new instance from bytes.
124      *
125      * @param bytes the bytes to store as a ZipLong
126      */

127     public ZipLong(final byte[] bytes) {
128         this(bytes, 0);
129     }
130
131     /**
132      * Creates instance from the four bytes starting at offset.
133      *
134      * @param bytes  the bytes to store as a ZipLong
135      * @param offset the offset to start
136      */

137     public ZipLong(final byte[] bytes, final int offset) {
138         value = ZipLong.getValue(bytes, offset);
139     }
140
141     /**
142      * create instance from a Java int.
143      *
144      * @param value the int to store as a ZipLong
145      * @since 1.15
146      */

147     public ZipLong(final int value) {
148         this.value = value;
149     }
150
151     /**
152      * Creates instance from a number.
153      *
154      * @param value the long to store as a ZipLong
155      */

156     public ZipLong(final long value) {
157         this.value = value;
158     }
159
160     @Override
161     public Object clone() {
162         try {
163             return super.clone();
164         } catch (final CloneNotSupportedException cnfe) {
165             // impossible
166             throw new UnsupportedOperationException(cnfe); // NOSONAR
167         }
168     }
169
170     /**
171      * Override to make two instances with same value equal.
172      *
173      * @param o an object to compare
174      * @return true if the objects are equal
175      */

176     @Override
177     public boolean equals(final Object o) {
178         if (!(o instanceof ZipLong)) {
179             return false;
180         }
181         return value == ((ZipLong) o).getValue();
182     }
183
184     /**
185      * Gets value as four bytes in big-endian byte order.
186      *
187      * @return value as four bytes in big-endian order
188      */

189     public byte[] getBytes() {
190         return ZipLong.getBytes(value);
191     }
192
193     /**
194      * Gets value as a (signed) Java int
195      *
196      * @return value as int
197      * @since 1.15
198      */

199     public int getIntValue() {
200         return (int) value;
201     }
202
203     /**
204      * Gets value as Java long.
205      *
206      * @return value as a long
207      */

208     public long getValue() {
209         return value;
210     }
211
212     /**
213      * Override to make two instances with same value equal.
214      *
215      * @return the value stored in the ZipLong
216      */

217     @Override
218     public int hashCode() {
219         return (int) value;
220     }
221
222     public void putLong(final byte[] buf, final int offset) {
223         putLong(value, buf, offset);
224     }
225
226     @Override
227     public String toString() {
228         return "ZipLong value: " + value;
229     }
230 }
231