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