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