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         * Data Descriptor signature
053         * @since Apache Commons Compress 1.1
054         */
055        public static final ZipLong DD_SIG = new ZipLong(0X08074B50L);
056    
057        /**
058         * Create instance from a number.
059         * @param value the long to store as a ZipLong
060         */
061        public ZipLong(long value) {
062            this.value = value;
063        }
064    
065        /**
066         * Create instance from bytes.
067         * @param bytes the bytes to store as a ZipLong
068         */
069        public ZipLong (byte[] bytes) {
070            this(bytes, 0);
071        }
072    
073        /**
074         * Create instance from the four bytes starting at offset.
075         * @param bytes the bytes to store as a ZipLong
076         * @param offset the offset to start
077         */
078        public ZipLong (byte[] bytes, int offset) {
079            value = ZipLong.getValue(bytes, offset);
080        }
081    
082        /**
083         * Get value as four bytes in big endian byte order.
084         * @return value as four bytes in big endian order
085         */
086        public byte[] getBytes() {
087            return ZipLong.getBytes(value);
088        }
089    
090        /**
091         * Get value as Java long.
092         * @return value as a long
093         */
094        public long getValue() {
095            return value;
096        }
097    
098        /**
099         * Get value as four bytes in big endian byte order.
100         * @param value the value to convert
101         * @return value as four bytes in big endian byte order
102         */
103        public static byte[] getBytes(long value) {
104            byte[] result = new byte[WORD];
105            result[0] = (byte) ((value & BYTE_MASK));
106            result[BYTE_1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
107            result[BYTE_2] = (byte) ((value & BYTE_2_MASK) >> BYTE_2_SHIFT);
108            result[BYTE_3] = (byte) ((value & BYTE_3_MASK) >> BYTE_3_SHIFT);
109            return result;
110        }
111    
112        /**
113         * Helper method to get the value as a Java long from four bytes starting at given array offset
114         * @param bytes the array of bytes
115         * @param offset the offset to start
116         * @return the corresponding Java long value
117         */
118        public static long getValue(byte[] bytes, int offset) {
119            long value = (bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
120            value += (bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
121            value += (bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
122            value += (bytes[offset] & BYTE_MASK);
123            return value;
124        }
125    
126        /**
127         * Helper method to get the value as a Java long from a four-byte array
128         * @param bytes the array of bytes
129         * @return the corresponding Java long value
130         */
131        public static long getValue(byte[] bytes) {
132            return getValue(bytes, 0);
133        }
134    
135        /**
136         * Override to make two instances with same value equal.
137         * @param o an object to compare
138         * @return true if the objects are equal
139         */
140        public boolean equals(Object o) {
141            if (o == null || !(o instanceof ZipLong)) {
142                return false;
143            }
144            return value == ((ZipLong) o).getValue();
145        }
146    
147        /**
148         * Override to make two instances with same value equal.
149         * @return the value stored in the ZipLong
150         */
151        public int hashCode() {
152            return (int) value;
153        }
154    
155        public Object clone() {
156            try {
157                return super.clone();
158            } catch (CloneNotSupportedException cnfe) {
159                // impossible
160                throw new RuntimeException(cnfe);
161            }
162        }
163    
164        public String toString() {
165            return "ZipLong value: " + value;
166        }
167    }