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 java.io.Serializable;
020
021import org.apache.commons.compress.utils.ByteUtils;
022
023/**
024 * Utility class that represents a two byte integer with conversion
025 * rules for the little endian byte order of ZIP files.
026 * @Immutable
027 */
028public final class ZipShort implements Cloneable, Serializable {
029    /**
030     * ZipShort with a value of 0.
031     * @since 1.14
032     */
033    public static final ZipShort ZERO = new ZipShort(0);
034
035    private static final long serialVersionUID = 1L;
036
037    /**
038     * Gets value as two bytes in big endian byte order.
039     * @param value the Java int to convert to bytes
040     * @return the converted int as a byte array in big endian byte order
041     */
042    public static byte[] getBytes(final int value) {
043        final byte[] result = new byte[2];
044        putShort(value, result, 0);
045        return result;
046    }
047
048    /**
049     * Helper method to get the value as a java int from a two-byte array
050     * @param bytes the array of bytes
051     * @return the corresponding java int value
052     */
053    public static int getValue(final byte[] bytes) {
054        return getValue(bytes, 0);
055    }
056
057    /**
058     * Helper method to get the value as a java int from two bytes starting at given array offset
059     * @param bytes the array of bytes
060     * @param offset the offset to start
061     * @return the corresponding java int value
062     */
063    public static int getValue(final byte[] bytes, final int offset) {
064        return (int) ByteUtils.fromLittleEndian(bytes, offset, 2);
065    }
066
067    /**
068     * put the value as two bytes in big endian byte order.
069     * @param value the Java int to convert to bytes
070     * @param buf the output buffer
071     * @param  offset
072     *         The offset within the output buffer of the first byte to be written.
073     *         must be non-negative and no larger than {@code buf.length-2}
074     */
075    public static void putShort(final int value, final byte[] buf, final int offset) {
076        ByteUtils.toLittleEndian(buf, value, offset, 2);
077    }
078
079    private final int value;
080
081    /**
082     * Create instance from bytes.
083     * @param bytes the bytes to store as a ZipShort
084     */
085    public ZipShort(final byte[] bytes) {
086        this(bytes, 0);
087    }
088
089    /**
090     * Create instance from the two bytes starting at offset.
091     * @param bytes the bytes to store as a ZipShort
092     * @param offset the offset to start
093     */
094    public ZipShort(final byte[] bytes, final int offset) {
095        value = ZipShort.getValue(bytes, offset);
096    }
097
098    /**
099     * Create instance from a number.
100     * @param value the int to store as a ZipShort
101     */
102    public ZipShort(final int value) {
103        this.value = value;
104    }
105
106    @Override
107    public Object clone() {
108        try {
109            return super.clone();
110        } catch (final CloneNotSupportedException cnfe) {
111            // impossible
112            throw new UnsupportedOperationException(cnfe); //NOSONAR
113        }
114    }
115
116    /**
117     * Override to make two instances with same value equal.
118     * @param o an object to compare
119     * @return true if the objects are equal
120     */
121    @Override
122    public boolean equals(final Object o) {
123        if (!(o instanceof ZipShort)) {
124            return false;
125        }
126        return value == ((ZipShort) o).getValue();
127    }
128
129    /**
130     * Gets value as two bytes in big endian byte order.
131     * @return the value as a two byte array in big endian byte order
132     */
133    public byte[] getBytes() {
134        final byte[] result = new byte[2];
135        ByteUtils.toLittleEndian(result, value, 0, 2);
136        return result;
137    }
138
139    /**
140     * Gets value as Java int.
141     * @return value as a Java int
142     */
143    public int getValue() {
144        return value;
145    }
146
147    /**
148     * Override to make two instances with same value equal.
149     * @return the value stored in the ZipShort
150     */
151    @Override
152    public int hashCode() {
153        return value;
154    }
155
156    @Override
157    public String toString() {
158        return "ZipShort value: " + value;
159    }
160}