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