1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.commons.compress.archivers.zip;
20
21 import java.io.Serializable;
22
23 import org.apache.commons.compress.utils.ByteUtils;
24 import org.apache.commons.lang3.ArrayUtils;
25
26 /**
27 * Utility class that represents a two byte integer with conversion rules for the little-endian byte order of ZIP files.
28 *
29 * @Immutable
30 */
31 public final class ZipShort implements Cloneable, Serializable {
32
33 private static final int SIZE = 2;
34
35 /**
36 * ZipShort with a value of 0.
37 *
38 * @since 1.14
39 */
40 public static final ZipShort ZERO = new ZipShort(0);
41
42 private static final long serialVersionUID = 1L;
43
44 /**
45 * Gets value as two bytes in big-endian byte order.
46 *
47 * @param value the Java int to convert to bytes
48 * @return the converted int as a byte array in big-endian byte order
49 */
50 public static byte[] getBytes(final int value) {
51 final byte[] result = new byte[SIZE];
52 putShort(value, result, 0);
53 return result;
54 }
55
56 /**
57 * Helper method to get the value as a Java int from a two-byte array
58 *
59 * @param bytes the array of bytes
60 * @return the corresponding Java int value
61 */
62 public static int getValue(final byte[] bytes) {
63 return getValue(bytes, 0);
64 }
65
66 /**
67 * Helper method to get the value as a Java int from two bytes starting at given array offset
68 *
69 * @param bytes the array of bytes
70 * @param offset the offset to start
71 * @return the corresponding Java int value
72 */
73 public static int getValue(final byte[] bytes, final int offset) {
74 return (int) ByteUtils.fromLittleEndian(bytes, offset, SIZE);
75 }
76
77 static ZipShort lengthOf(final byte[] array) {
78 return new ZipShort(ArrayUtils.getLength(array));
79 }
80
81 /**
82 * put the value as two bytes in big-endian byte order.
83 *
84 * @param value the Java int to convert to bytes
85 * @param buf the output buffer
86 * @param offset The offset within the output buffer of the first byte to be written. must be non-negative and no larger than {@code buf.length-2}
87 */
88 public static void putShort(final int value, final byte[] buf, final int offset) {
89 ByteUtils.toLittleEndian(buf, value, offset, SIZE);
90 }
91
92 private final int value;
93
94 /**
95 * Constructs a new instance from bytes.
96 *
97 * @param bytes the bytes to store as a ZipShort
98 */
99 public ZipShort(final byte[] bytes) {
100 this(bytes, 0);
101 }
102
103 /**
104 * Constructs a new instance from the two bytes starting at offset.
105 *
106 * @param bytes the bytes to store as a ZipShort
107 * @param offset the offset to start
108 */
109 public ZipShort(final byte[] bytes, final int offset) {
110 value = getValue(bytes, offset);
111 }
112
113 /**
114 * Constructs a new instance from a number.
115 *
116 * @param value the int to store as a ZipShort
117 */
118 public ZipShort(final int value) {
119 this.value = value;
120 }
121
122 @Override
123 public Object clone() {
124 try {
125 return super.clone();
126 } catch (final CloneNotSupportedException cnfe) {
127 // impossible
128 throw new UnsupportedOperationException(cnfe); // NOSONAR
129 }
130 }
131
132 /**
133 * Override to make two instances with same value equal.
134 *
135 * @param o an object to compare
136 * @return true if the objects are equal
137 */
138 @Override
139 public boolean equals(final Object o) {
140 if (!(o instanceof ZipShort)) {
141 return false;
142 }
143 return value == ((ZipShort) o).getValue();
144 }
145
146 /**
147 * Gets value as two bytes in big-endian byte order.
148 *
149 * @return the value as a two byte array in big-endian byte order
150 */
151 public byte[] getBytes() {
152 final byte[] result = new byte[SIZE];
153 ByteUtils.toLittleEndian(result, value, 0, SIZE);
154 return result;
155 }
156
157 /**
158 * Gets value as Java int.
159 *
160 * @return value as a Java int
161 */
162 public int getValue() {
163 return value;
164 }
165
166 /**
167 * Override to make two instances with same value equal.
168 *
169 * @return the value stored in the ZipShort
170 */
171 @Override
172 public int hashCode() {
173 return value;
174 }
175
176 @Override
177 public String toString() {
178 return "ZipShort value: " + value;
179 }
180 }