    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}