    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 *
    017 */
    018package org.apache.commons.compress.archivers.zip;
    019
    020import java.io.Serializable;
    021import java.math.BigInteger;
    022
    023import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;
    024
    025/**
    026 * Utility class that represents an eight byte integer with conversion
    027 * rules for the little endian byte order of ZIP files.
    028 * @Immutable
    029 *
    030 * @since 1.2
    031 */
    032public final class ZipEightByteInteger implements Serializable {
    033    private static final long serialVersionUID = 1L;
    034
    035    private static final int BYTE_1 = 1;
    036    private static final int BYTE_1_MASK = 0xFF00;
    037    private static final int BYTE_1_SHIFT = 8;
    038
    039    private static final int BYTE_2 = 2;
    040    private static final int BYTE_2_MASK = 0xFF0000;
    041    private static final int BYTE_2_SHIFT = 16;
    042
    043    private static final int BYTE_3 = 3;
    044    private static final long BYTE_3_MASK = 0xFF000000L;
    045    private static final int BYTE_3_SHIFT = 24;
    046
    047    private static final int BYTE_4 = 4;
    048    private static final long BYTE_4_MASK = 0xFF00000000L;
    049    private static final int BYTE_4_SHIFT = 32;
    050
    051    private static final int BYTE_5 = 5;
    052    private static final long BYTE_5_MASK = 0xFF0000000000L;
    053    private static final int BYTE_5_SHIFT = 40;
    054
    055    private static final int BYTE_6 = 6;
    056    private static final long BYTE_6_MASK = 0xFF000000000000L;
    057    private static final int BYTE_6_SHIFT = 48;
    058
    059    private static final int BYTE_7 = 7;
    060    private static final long BYTE_7_MASK = 0x7F00000000000000L;
    061    private static final int BYTE_7_SHIFT = 56;
    062
    063    private static final int LEFTMOST_BIT_SHIFT = 63;
    064    private static final byte LEFTMOST_BIT = (byte) 0x80;
    065
    066    private final BigInteger value;
    067
    068    public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0);
    069
    070    /**
    071     * Create instance from a number.
    072     * @param value the long to store as a ZipEightByteInteger
    073     */
    074    public ZipEightByteInteger(final long value) {
    075        this(BigInteger.valueOf(value));
    076    }
    077
    078    /**
    079     * Create instance from a number.
    080     * @param value the BigInteger to store as a ZipEightByteInteger
    081     */
    082    public ZipEightByteInteger(final BigInteger value) {
    083        this.value = value;
    084    }
    085
    086    /**
    087     * Create instance from bytes.
    088     * @param bytes the bytes to store as a ZipEightByteInteger
    089     */
    090    public ZipEightByteInteger (final byte[] bytes) {
    091        this(bytes, 0);
    092    }
    093
    094    /**
    095     * Create instance from the eight bytes starting at offset.
    096     * @param bytes the bytes to store as a ZipEightByteInteger
    097     * @param offset the offset to start
    098     */
    099    public ZipEightByteInteger (final byte[] bytes, final int offset) {
    100        value = ZipEightByteInteger.getValue(bytes, offset);
    101    }
    102
    103    /**
    104     * Get value as eight bytes in big endian byte order.
    105     * @return value as eight bytes in big endian order
    106     */
    107    public byte[] getBytes() {
    108        return ZipEightByteInteger.getBytes(value);
    109    }
    110
    111    /**
    112     * Get value as Java long.
    113     * @return value as a long
    114     */
    115    public long getLongValue() {
    116        return value.longValue();
    117    }
    118
    119    /**
    120     * Get value as Java BigInteger.
    121     * @return value as a BigInteger
    122     */
    123    public BigInteger getValue() {
    124        return value;
    125    }
    126
    127    /**
    128     * Get value as eight bytes in big endian byte order.
    129     * @param value the value to convert
    130     * @return value as eight bytes in big endian byte order
    131     */
    132    public static byte[] getBytes(final long value) {
    133        return getBytes(BigInteger.valueOf(value));
    134    }
    135
    136    /**
    137     * Get value as eight bytes in big endian byte order.
    138     * @param value the value to convert
    139     * @return value as eight bytes in big endian byte order
    140     */
    141    public static byte[] getBytes(final BigInteger value) {
    142        final byte[] result = new byte[8];
    143        final long val = value.longValue();
    144        result[0] = (byte) ((val & BYTE_MASK));
    145        result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT);
    146        result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT);
    147        result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT);
    148        result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT);
    149        result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT);
    150        result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT);
    151        result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT);
    152        if (value.testBit(LEFTMOST_BIT_SHIFT)) {
    153            result[BYTE_7] |= LEFTMOST_BIT;
    154        }
    155        return result;
    156    }
    157
    158    /**
    159     * Helper method to get the value as a Java long from eight bytes
    160     * starting at given array offset
    161     * @param bytes the array of bytes
    162     * @param offset the offset to start
    163     * @return the corresponding Java long value
    164     */
    165    public static long getLongValue(final byte[] bytes, final int offset) {
    166        return getValue(bytes, offset).longValue();
    167    }
    168
    169    /**
    170     * Helper method to get the value as a Java BigInteger from eight
    171     * bytes starting at given array offset
    172     * @param bytes the array of bytes
    173     * @param offset the offset to start
    174     * @return the corresponding Java BigInteger value
    175     */
    176    public static BigInteger getValue(final byte[] bytes, final int offset) {
    177        long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK;
    178        value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK;
    179        value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK;
    180        value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK;
    181        value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
    182        value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
    183        value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
    184        value += ((long) bytes[offset] & BYTE_MASK);
    185        final BigInteger val = BigInteger.valueOf(value);
    186        return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT
    187            ? val.setBit(LEFTMOST_BIT_SHIFT) : val;
    188    }
    189
    190    /**
    191     * Helper method to get the value as a Java long from an eight-byte array
    192     * @param bytes the array of bytes
    193     * @return the corresponding Java long value
    194     */
    195    public static long getLongValue(final byte[] bytes) {
    196        return getLongValue(bytes, 0);
    197    }
    198
    199    /**
    200     * Helper method to get the value as a Java long from an eight-byte array
    201     * @param bytes the array of bytes
    202     * @return the corresponding Java BigInteger value
    203     */
    204    public static BigInteger getValue(final byte[] bytes) {
    205        return getValue(bytes, 0);
    206    }
    207
    208    /**
    209     * Override to make two instances with same value equal.
    210     * @param o an object to compare
    211     * @return true if the objects are equal
    212     */
    213    @Override
    214    public boolean equals(final Object o) {
    215        if (!(o instanceof ZipEightByteInteger)) {
    216            return false;
    217        }
    218        return value.equals(((ZipEightByteInteger) o).getValue());
    219    }
    220
    221    /**
    222     * Override to make two instances with same value equal.
    223     * @return the hashCode of the value stored in the ZipEightByteInteger
    224     */
    225    @Override
    226    public int hashCode() {
    227        return value.hashCode();
    228    }
    229
    230    @Override
    231    public String toString() {
    232        return "ZipEightByteInteger value: " + value;
    233    }
    234}