    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 java.io.Serializable;
    022import java.math.BigInteger;
    023import java.nio.ByteBuffer;
    024import java.nio.ByteOrder;
    025
    026/**
    027 * Utility class that represents an eight byte integer with conversion rules for the little-endian byte order of ZIP files.
    028 *
    029 * @Immutable
    030 * @since 1.2
    031 */
    032public final class ZipEightByteInteger implements Serializable {
    033
    034    /**
    035     *  The number of bytes used to represent an instance in binary form.
    036     */
    037    static final int BYTES = 8;
    038
    039    private static final long serialVersionUID = 1L;
    040
    041    /**
    042     * Constant for a value of zero.
    043     */
    044    public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0);
    045
    046    private static final BigInteger HIGHEST_BIT = BigInteger.ONE.shiftLeft(63);
    047
    048    /**
    049     * Gets value as eight bytes in big-endian byte order.
    050     *
    051     * @param value the value to convert.
    052     * @return value as eight bytes in big-endian byte order.
    053     */
    054    public static byte[] getBytes(final BigInteger value) {
    055        return getBytes(value.longValue());
    056    }
    057
    058    /**
    059     * Gets value as eight bytes in big-endian byte order.
    060     *
    061     * @param value the value to convert.
    062     * @return value as eight bytes in big-endian byte order.
    063     */
    064    public static byte[] getBytes(final long value) {
    065        return ByteBuffer.allocate(BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(value).array();
    066    }
    067
    068    /**
    069     * Gets the value as a Java long from an eight-byte array.
    070     *
    071     * @param bytes the array of bytes.
    072     * @return the corresponding Java long value.
    073     */
    074    public static long getLongValue(final byte[] bytes) {
    075        return getLongValue(bytes, 0);
    076    }
    077
    078    /**
    079     * Gets the value as a Java long from eight bytes starting at given array offset.
    080     *
    081     * @param bytes  the array of bytes.
    082     * @param offset the offset to start.
    083     * @return the corresponding Java long value.
    084     */
    085    public static long getLongValue(final byte[] bytes, final int offset) {
    086        return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getLong(offset);
    087    }
    088
    089    /**
    090     * Gets the value as a Java long from an eight-byte array.
    091     *
    092     * @param bytes the array of bytes.
    093     * @return the corresponding Java BigInteger value.
    094     */
    095    public static BigInteger getValue(final byte[] bytes) {
    096        return getValue(bytes, 0);
    097    }
    098
    099    /**
    100     * Gets the value as a Java BigInteger from eight bytes starting at given array offset.
    101     *
    102     * @param bytes  the array of bytes.
    103     * @param offset the offset to start.
    104     * @return the corresponding Java BigInteger value.
    105     */
    106    public static BigInteger getValue(final byte[] bytes, final int offset) {
    107        return toUnsignedBigInteger(getLongValue(bytes, offset));
    108    }
    109
    110    /**
    111     * package private for tests only.
    112     */
    113    static BigInteger toUnsignedBigInteger(final long value) {
    114        if (value >= 0L) {
    115            return BigInteger.valueOf(value);
    116        }
    117        return BigInteger.valueOf(value & Long.MAX_VALUE).add(HIGHEST_BIT);
    118    }
    119
    120    /**
    121     * The value is treated as unsigned.
    122     */
    123    private final long value;
    124
    125    /**
    126     * Constructs a new instance from a number.
    127     *
    128     * @param value the BigInteger to store as a ZipEightByteInteger
    129     */
    130    public ZipEightByteInteger(final BigInteger value) {
    131        this.value = value.longValue();
    132    }
    133
    134    /**
    135     * Constructs a new instance from bytes.
    136     *
    137     * @param bytes the bytes to store as a ZipEightByteInteger.
    138     */
    139    public ZipEightByteInteger(final byte[] bytes) {
    140        this(bytes, 0);
    141    }
    142
    143    /**
    144     * Constructs a new instance from the eight bytes starting at offset.
    145     *
    146     * @param bytes  the bytes to store as a ZipEightByteInteger.
    147     * @param offset the offset to start.
    148     */
    149    public ZipEightByteInteger(final byte[] bytes, final int offset) {
    150        this.value = getLongValue(bytes, offset);
    151    }
    152
    153    /**
    154     * Constructs a new instance from a number.
    155     *
    156     * @param value the long to store as a ZipEightByteInteger.
    157     */
    158    public ZipEightByteInteger(final long value) {
    159        this.value = value;
    160    }
    161
    162    /**
    163     * Override to make two instances with same value equal.
    164     *
    165     * @param o an object to compare.
    166     * @return true if the objects are equal.
    167     */
    168    @Override
    169    public boolean equals(final Object o) {
    170        if (!(o instanceof ZipEightByteInteger)) {
    171            return false;
    172        }
    173        return value == ((ZipEightByteInteger) o).value;
    174    }
    175
    176    /**
    177     * Gets value as eight bytes in big-endian byte order.
    178     *
    179     * @return value as eight bytes in big-endian order.
    180     */
    181    public byte[] getBytes() {
    182        return getBytes(value);
    183    }
    184
    185    /**
    186     * Gets value as Java long.
    187     *
    188     * @return value as a long.
    189     */
    190    public long getLongValue() {
    191        return value;
    192    }
    193
    194    /**
    195     * Gets value as Java BigInteger.
    196     *
    197     * @return value as a BigInteger.
    198     */
    199    public BigInteger getValue() {
    200        return toUnsignedBigInteger(value);
    201    }
    202
    203    /**
    204     * Override to make two instances with same value equal.
    205     *
    206     * @return the hash code of the value stored in the ZipEightByteInteger.
    207     */
    208    @Override
    209    public int hashCode() {
    210        return Long.hashCode(value);
    211    }
    212
    213    @Override
    214    public String toString() {
    215        return Long.toUnsignedString(value);
    216    }
    217}