    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 static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;
    021
    022import java.io.Serializable;
    023import java.math.BigInteger;
    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    public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0);
    067
    068    /**
    069     * Get value as eight bytes in big endian byte order.
    070     * @param value the value to convert
    071     * @return value as eight bytes in big endian byte order
    072     */
    073    public static byte[] getBytes(final BigInteger value) {
    074        final byte[] result = new byte[8];
    075        final long val = value.longValue();
    076        result[0] = (byte) ((val & BYTE_MASK));
    077        result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT);
    078        result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT);
    079        result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT);
    080        result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT);
    081        result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT);
    082        result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT);
    083        result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT);
    084        if (value.testBit(LEFTMOST_BIT_SHIFT)) {
    085            result[BYTE_7] |= LEFTMOST_BIT;
    086        }
    087        return result;
    088    }
    089
    090    /**
    091     * Get value as eight bytes in big endian byte order.
    092     * @param value the value to convert
    093     * @return value as eight bytes in big endian byte order
    094     */
    095    public static byte[] getBytes(final long value) {
    096        return getBytes(BigInteger.valueOf(value));
    097    }
    098
    099    /**
    100     * Helper method to get the value as a Java long from an eight-byte array
    101     * @param bytes the array of bytes
    102     * @return the corresponding Java long value
    103     */
    104    public static long getLongValue(final byte[] bytes) {
    105        return getLongValue(bytes, 0);
    106    }
    107
    108    /**
    109     * Helper method to get the value as a Java long from eight bytes
    110     * starting at given array offset
    111     * @param bytes the array of bytes
    112     * @param offset the offset to start
    113     * @return the corresponding Java long value
    114     */
    115    public static long getLongValue(final byte[] bytes, final int offset) {
    116        return getValue(bytes, offset).longValue();
    117    }
    118
    119    /**
    120     * Helper method to get the value as a Java long from an eight-byte array
    121     * @param bytes the array of bytes
    122     * @return the corresponding Java BigInteger value
    123     */
    124    public static BigInteger getValue(final byte[] bytes) {
    125        return getValue(bytes, 0);
    126    }
    127
    128    /**
    129     * Helper method to get the value as a Java BigInteger from eight
    130     * bytes starting at given array offset
    131     * @param bytes the array of bytes
    132     * @param offset the offset to start
    133     * @return the corresponding Java BigInteger value
    134     */
    135    public static BigInteger getValue(final byte[] bytes, final int offset) {
    136        long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK;
    137        value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK;
    138        value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK;
    139        value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK;
    140        value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
    141        value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
    142        value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
    143        value += ((long) bytes[offset] & BYTE_MASK);
    144        final BigInteger val = BigInteger.valueOf(value);
    145        return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT
    146            ? val.setBit(LEFTMOST_BIT_SHIFT) : val;
    147    }
    148
    149    private final BigInteger value;
    150
    151    /**
    152     * Create instance from a number.
    153     * @param value the BigInteger to store as a ZipEightByteInteger
    154     */
    155    public ZipEightByteInteger(final BigInteger value) {
    156        this.value = value;
    157    }
    158
    159    /**
    160     * Create instance from bytes.
    161     * @param bytes the bytes to store as a ZipEightByteInteger
    162     */
    163    public ZipEightByteInteger (final byte[] bytes) {
    164        this(bytes, 0);
    165    }
    166
    167    /**
    168     * Create instance from the eight bytes starting at offset.
    169     * @param bytes the bytes to store as a ZipEightByteInteger
    170     * @param offset the offset to start
    171     */
    172    public ZipEightByteInteger (final byte[] bytes, final int offset) {
    173        value = ZipEightByteInteger.getValue(bytes, offset);
    174    }
    175
    176    /**
    177     * Create instance from a number.
    178     * @param value the long to store as a ZipEightByteInteger
    179     */
    180    public ZipEightByteInteger(final long value) {
    181        this(BigInteger.valueOf(value));
    182    }
    183
    184    /**
    185     * Override to make two instances with same value equal.
    186     * @param o an object to compare
    187     * @return true if the objects are equal
    188     */
    189    @Override
    190    public boolean equals(final Object o) {
    191        if (!(o instanceof ZipEightByteInteger)) {
    192            return false;
    193        }
    194        return value.equals(((ZipEightByteInteger) o).getValue());
    195    }
    196
    197    /**
    198     * Get value as eight bytes in big endian byte order.
    199     * @return value as eight bytes in big endian order
    200     */
    201    public byte[] getBytes() {
    202        return ZipEightByteInteger.getBytes(value);
    203    }
    204
    205    /**
    206     * Get value as Java long.
    207     * @return value as a long
    208     */
    209    public long getLongValue() {
    210        return value.longValue();
    211    }
    212
    213    /**
    214     * Get value as Java BigInteger.
    215     * @return value as a BigInteger
    216     */
    217    public BigInteger getValue() {
    218        return value;
    219    }
    220
    221    /**
    222     * Override to make two instances with same value equal.
    223     * @return the hash code 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}