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