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 */
017package org.apache.commons.compress.archivers.zip;
018
019import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
020
021import java.io.Serializable;
022
023import org.apache.commons.compress.utils.ByteUtils;
024
025/**
026 * Utility class that represents a four byte integer with conversion rules for the little-endian byte order of ZIP files.
027 *
028 * @Immutable
029 */
030public final class ZipLong implements Cloneable, Serializable {
031    private static final long serialVersionUID = 1L;
032
033    /** Central File Header Signature */
034    public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L);
035
036    /** Local File Header Signature */
037    public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L);
038
039    /**
040     * Data Descriptor signature.
041     *
042     * <p>
043     * Actually, PKWARE uses this as marker for split/spanned archives and other archivers have started to use it as Data Descriptor signature (as well).
044     * </p>
045     *
046     * @since 1.1
047     */
048    public static final ZipLong DD_SIG = new ZipLong(0X08074B50L);
049
050    /**
051     * Value stored in size and similar fields if ZIP64 extensions are used.
052     *
053     * @since 1.3
054     */
055    static final ZipLong ZIP64_MAGIC = new ZipLong(ZipConstants.ZIP64_MAGIC);
056
057    /**
058     * 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).
059     *
060     * <p>
061     * This is the "PK00" prefix found in some archives.
062     * </p>
063     *
064     * @since 1.5
065     */
066    public static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER = new ZipLong(0X30304B50L);
067
068    /**
069     * Archive extra data record signature.
070     *
071     * @since 1.5
072     */
073    public static final ZipLong AED_SIG = new ZipLong(0X08064B50L);
074
075    /**
076     * Gets value as four bytes in big-endian byte order.
077     *
078     * @param value the value to convert
079     * @return value as four bytes in big-endian byte order
080     */
081    public static byte[] getBytes(final long value) {
082        final byte[] result = new byte[WORD];
083        putLong(value, result, 0);
084        return result;
085    }
086
087    /**
088     * Helper method to get the value as a Java long from a four-byte array
089     *
090     * @param bytes the array of bytes
091     * @return the corresponding Java long value
092     */
093    public static long getValue(final byte[] bytes) {
094        return getValue(bytes, 0);
095    }
096
097    /**
098     * Helper method to get the value as a Java long from four bytes starting at given array offset
099     *
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}