001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.archivers.zip;
020
021import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
022
023import java.io.Serializable;
024
025import org.apache.commons.compress.utils.ByteUtils;
026
027/**
028 * Utility class that represents a four byte integer with conversion rules for the little-endian byte order of ZIP files.
029 *
030 * @Immutable
031 */
032public final class ZipLong implements Cloneable, Serializable {
033
034    private static final long serialVersionUID = 1L;
035
036    /** Central File Header Signature */
037    public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L);
038
039    /** Local File Header Signature */
040    public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L);
041
042    /**
043     * Data Descriptor signature.
044     *
045     * <p>
046     * Actually, PKWARE uses this as marker for split/spanned archives and other archivers have started to use it as Data Descriptor signature (as well).
047     * </p>
048     *
049     * @since 1.1
050     */
051    public static final ZipLong DD_SIG = new ZipLong(0X08074B50L);
052
053    /**
054     * Value stored in size and similar fields if ZIP64 extensions are used.
055     *
056     * @since 1.3
057     */
058    static final ZipLong ZIP64_MAGIC = new ZipLong(ZipConstants.ZIP64_MAGIC);
059
060    /**
061     * 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).
062     *
063     * <p>
064     * This is the "PK00" prefix found in some archives.
065     * </p>
066     *
067     * @since 1.5
068     */
069    public static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER = new ZipLong(0X30304B50L);
070
071    /**
072     * Archive extra data record signature.
073     *
074     * @since 1.5
075     */
076    public static final ZipLong AED_SIG = new ZipLong(0X08064B50L);
077
078    /**
079     * Gets value as four bytes in big-endian byte order.
080     *
081     * @param value the value to convert
082     * @return value as four bytes in big-endian byte order
083     */
084    public static byte[] getBytes(final long value) {
085        final byte[] result = new byte[WORD];
086        putLong(value, result, 0);
087        return result;
088    }
089
090    /**
091     * Helper method to get the value as a Java long from a four-byte array
092     *
093     * @param bytes the array of bytes
094     * @return the corresponding Java long value
095     */
096    public static long getValue(final byte[] bytes) {
097        return getValue(bytes, 0);
098    }
099
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}