    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 static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;
    021
    022    /**
    023     * Utility class that represents a two byte integer with conversion
    024     * rules for the big endian byte order of ZIP files.
    025     * @Immutable
    026     */
    027    public final class ZipShort implements Cloneable {
    028        private static final int BYTE_1_MASK = 0xFF00;
    029        private static final int BYTE_1_SHIFT = 8;
    030
    031        private final int value;
    032
    033        /**
    034         * Create instance from a number.
    035         * @param value the int to store as a ZipShort
    036         */
    037        public ZipShort (int value) {
    038            this.value = value;
    039        }
    040
    041        /**
    042         * Create instance from bytes.
    043         * @param bytes the bytes to store as a ZipShort
    044         */
    045        public ZipShort (byte[] bytes) {
    046            this(bytes, 0);
    047        }
    048
    049        /**
    050         * Create instance from the two bytes starting at offset.
    051         * @param bytes the bytes to store as a ZipShort
    052         * @param offset the offset to start
    053         */
    054        public ZipShort (byte[] bytes, int offset) {
    055            value = ZipShort.getValue(bytes, offset);
    056        }
    057
    058        /**
    059         * Get value as two bytes in big endian byte order.
    060         * @return the value as a a two byte array in big endian byte order
    061         */
    062        public byte[] getBytes() {
    063            byte[] result = new byte[2];
    064            result[0] = (byte) (value & BYTE_MASK);
    065            result[1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
    066            return result;
    067        }
    068
    069        /**
    070         * Get value as Java int.
    071         * @return value as a Java int
    072         */
    073        public int getValue() {
    074            return value;
    075        }
    076
    077        /**
    078         * Get value as two bytes in big endian byte order.
    079         * @param value the Java int to convert to bytes
    080         * @return the converted int as a byte array in big endian byte order
    081         */
    082        public static byte[] getBytes(int value) {
    083            byte[] result = new byte[2];
    084            result[0] = (byte) (value & BYTE_MASK);
    085            result[1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
    086            return result;
    087        }
    088
    089        /**
    090         * Helper method to get the value as a java int from two bytes starting at given array offset
    091         * @param bytes the array of bytes
    092         * @param offset the offset to start
    093         * @return the corresponding java int value
    094         */
    095        public static int getValue(byte[] bytes, int offset) {
    096            int value = (bytes[offset + 1] << BYTE_1_SHIFT) & BYTE_1_MASK;
    097            value += (bytes[offset] & BYTE_MASK);
    098            return value;
    099        }
    100
    101        /**
    102         * Helper method to get the value as a java int from a two-byte array
    103         * @param bytes the array of bytes
    104         * @return the corresponding java int value
    105         */
    106        public static int getValue(byte[] bytes) {
    107            return getValue(bytes, 0);
    108        }
    109
    110        /**
    111         * Override to make two instances with same value equal.
    112         * @param o an object to compare
    113         * @return true if the objects are equal
    114         */
    115        @Override
    116        public boolean equals(Object o) {
    117            if (o == null || !(o instanceof ZipShort)) {
    118                return false;
    119            }
    120            return value == ((ZipShort) o).getValue();
    121        }
    122
    123        /**
    124         * Override to make two instances with same value equal.
    125         * @return the value stored in the ZipShort
    126         */
    127        @Override
    128        public int hashCode() {
    129            return value;
    130        }
    131
    132        @Override
    133        public Object clone() {
    134            try {
    135                return super.clone();
    136            } catch (CloneNotSupportedException cnfe) {
    137                // impossible
    138                throw new RuntimeException(cnfe);
    139            }
    140        }
    141
    142        @Override
    143        public String toString() {
    144            return "ZipShort value: " + value;
    145        }
    146    }