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 */
017package org.apache.commons.compress.archivers.zip;
018
019import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
020
021import java.io.Serializable;
022
023import org.apache.commons.compress.utils.ByteUtils;
024
025/**
026 * Utility class that represents a four byte integer with conversion
027 * rules for the little endian byte order of ZIP files.
028 * @Immutable
029 */
030public final class ZipLong implements Cloneable, Serializable {
031    private static final long serialVersionUID = 1L;
032
033    /** Central File Header Signature */
034    public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L);
035
036    /** Local File Header Signature */
037    public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L);
038
039    /**
040     * Data Descriptor signature.
041     *
042     * <p>Actually, PKWARE uses this as marker for split/spanned
043     * archives and other archivers have started to use it as Data
044     * Descriptor signature (as well).</p>
045     * @since 1.1
046     */
047    public static final ZipLong DD_SIG = new ZipLong(0X08074B50L);
048
049    /**
050     * Value stored in size and similar fields if ZIP64 extensions are
051     * used.
052     * @since 1.3
053     */
054    static final ZipLong ZIP64_MAGIC = new ZipLong(ZipConstants.ZIP64_MAGIC);
055
056    /**
057     * Marks ZIP archives that were supposed to be split or spanned
058     * but only needed a single segment in then end (so are actually
059     * neither split nor spanned).
060     *
061     * <p>This is the "PK00" prefix found in some archives.</p>
062     * @since 1.5
063     */
064    public static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER =
065        new ZipLong(0X30304B50L);
066
067    /**
068     * Archive extra data record signature.
069     * @since 1.5
070     */
071    public static final ZipLong AED_SIG = new ZipLong(0X08064B50L);
072
073    /**
074     * Gets value as four bytes in big endian byte order.
075     * @param value the value to convert
076     * @return value as four bytes in big endian byte order
077     */
078    public static byte[] getBytes(final long value) {
079        final byte[] result = new byte[WORD];
080        putLong(value, result, 0);
081        return result;
082    }
083
084    /**
085     * Helper method to get the value as a Java long from a four-byte array
086     * @param bytes the array of bytes
087     * @return the corresponding Java long value
088     */
089    public static long getValue(final byte[] bytes) {
090        return getValue(bytes, 0);
091    }
092
093    /**
094     * Helper method to get the value as a Java long from four bytes starting at given array offset
095     * @param bytes the array of bytes
096     * @param offset the offset to start
097     * @return the corresponding Java long value
098     */
099    public static long getValue(final byte[] bytes, final int offset) {
100        return ByteUtils.fromLittleEndian(bytes, offset, 4);
101    }
102
103    /**
104     * put the value as four bytes in big endian byte order.
105     * @param value the Java long to convert to bytes
106     * @param buf the output buffer
107     * @param  offset
108     *         The offset within the output buffer of the first byte to be written.
109     *         must be non-negative and no larger than {@code buf.length-4}
110     */
111
112    public static void putLong(final long value, final byte[] buf, final int offset) {
113        ByteUtils.toLittleEndian(buf, value, offset, 4);
114    }
115
116    private final long value;
117
118    /**
119     * Create instance from bytes.
120     * @param bytes the bytes to store as a ZipLong
121     */
122    public ZipLong(final byte[] bytes) {
123        this(bytes, 0);
124    }
125
126    /**
127     * Create instance from the four bytes starting at offset.
128     * @param bytes the bytes to store as a ZipLong
129     * @param offset the offset to start
130     */
131    public ZipLong(final byte[] bytes, final int offset) {
132        value = ZipLong.getValue(bytes, offset);
133    }
134
135    /**
136     * create instance from a java int.
137     * @param value the int to store as a ZipLong
138     * @since 1.15
139     */
140    public ZipLong(final int value) {
141        this.value = value;
142    }
143
144    /**
145     * Create instance from a number.
146     * @param value the long to store as a ZipLong
147     */
148    public ZipLong(final long value) {
149        this.value = value;
150    }
151
152    @Override
153    public Object clone() {
154        try {
155            return super.clone();
156        } catch (final CloneNotSupportedException cnfe) {
157            // impossible
158            throw new UnsupportedOperationException(cnfe); //NOSONAR
159        }
160    }
161
162    /**
163     * Override to make two instances with same value equal.
164     * @param o an object to compare
165     * @return true if the objects are equal
166     */
167    @Override
168    public boolean equals(final Object o) {
169        if (!(o instanceof ZipLong)) {
170            return false;
171        }
172        return value == ((ZipLong) o).getValue();
173    }
174
175    /**
176     * Gets value as four bytes in big endian byte order.
177     * @return value as four bytes in big endian order
178     */
179    public byte[] getBytes() {
180        return ZipLong.getBytes(value);
181    }
182
183    /**
184     * Gets value as a (signed) java int
185     * @return value as int
186     * @since 1.15
187     */
188    public int getIntValue() { return (int) value;}
189
190    /**
191     * Gets value as Java long.
192     * @return value as a long
193     */
194    public long getValue() {
195        return value;
196    }
197
198    /**
199     * Override to make two instances with same value equal.
200     * @return the value stored in the ZipLong
201     */
202    @Override
203    public int hashCode() {
204        return (int) value;
205    }
206
207    public void putLong(final byte[] buf, final int offset) {
208        putLong(value, buf, offset);
209    }
210
211    @Override
212    public String toString() {
213        return "ZipLong value: " + value;
214    }
215}