1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 /**
4  *******************************************************************************
5  * Copyright (C) 1996-2016, International Business Machines Corporation and    *
6  * others. All Rights Reserved.                                                *
7  *******************************************************************************
8  */
9 
10 package com.ibm.icu.util;
11 
12 import java.nio.ByteBuffer;
13 
14 import com.ibm.icu.impl.Utility;
15 
16 /**
17  * A simple utility class to wrap a byte array.
18  * <p>
19  * Generally passed as an argument object into a method. The method takes
20  * responsibility of writing into the internal byte array and increasing its
21  * size when necessary.
22  *
23  * @author syn wee
24  * @stable ICU 2.8
25  */
26 public class ByteArrayWrapper implements Comparable<ByteArrayWrapper>
27 {
28     // public data member ------------------------------------------------
29 
30     /**
31      * Internal byte array.
32      * @stable ICU 2.8
33      */
34     public byte[] bytes;
35 
36     /**
37      * Size of the internal byte array used.
38      * Different from bytes.length, size will be &lt;= bytes.length.
39      * Semantics of size is similar to java.util.Vector.size().
40      * @stable ICU 2.8
41      */
42     public int size;
43 
44     // public constructor ------------------------------------------------
45 
46     /**
47      * Construct a new ByteArrayWrapper with no data.
48      * @stable ICU 2.8
49      */
ByteArrayWrapper()50     public ByteArrayWrapper() {
51         // leave bytes null, don't allocate twice
52     }
53 
54     /**
55      * Construct a new ByteArrayWrapper from a byte array and size
56      * @param bytesToAdopt the byte array to adopt
57      * @param size the length of valid data in the byte array
58      * @throws IndexOutOfBoundsException if bytesToAdopt == null and size != 0, or
59      * size &lt; 0, or size &gt; bytesToAdopt.length.
60      * @stable ICU 3.2
61      */
ByteArrayWrapper(byte[] bytesToAdopt, int size)62     public ByteArrayWrapper(byte[] bytesToAdopt, int size) {
63         if ((bytesToAdopt == null && size != 0) || size < 0 || (bytesToAdopt != null && size > bytesToAdopt.length)) {
64             throw new IndexOutOfBoundsException("illegal size: " + size);
65         }
66         this.bytes = bytesToAdopt;
67         this.size = size;
68     }
69 
70     /**
71      * Construct a new ByteArrayWrapper from the contents of a ByteBuffer.
72      * @param source the ByteBuffer from which to get the data.
73      * @stable ICU 3.2
74      */
ByteArrayWrapper(ByteBuffer source)75     public ByteArrayWrapper(ByteBuffer source) {
76         size = source.limit();
77         bytes = new byte[size];
78         source.get(bytes,0,size);
79     }
80 
81     /**
82      * Create from ByteBuffer
83      * @param byteBuffer
84     public ByteArrayWrapper(ByteArrayWrapper source) {
85         size = source.size;
86         bytes = new byte[size];
87         copyBytes(source.bytes, 0, bytes, 0, size);
88     }
89      */
90 
91     /**
92      * create from byte buffer
93      * @param src
94      * @param start
95      * @param limit
96     public ByteArrayWrapper(byte[] src, int start, int limit) {
97         size = limit - start;
98         bytes = new byte[size];
99         copyBytes(src, start, bytes, 0, size);
100     }
101      */
102 
103     // public methods ----------------------------------------------------
104 
105     /**
106      * Ensure that the internal byte array is at least of length capacity.
107      * If the byte array is null or its length is less than capacity, a new
108      * byte array of length capacity will be allocated.
109      * The contents of the array (between 0 and size) remain unchanged.
110      * @param capacity minimum length of internal byte array.
111      * @return this ByteArrayWrapper
112      * @stable ICU 3.2
113      */
ensureCapacity(int capacity)114     public ByteArrayWrapper ensureCapacity(int capacity)
115     {
116         if (bytes == null || bytes.length < capacity) {
117             byte[] newbytes = new byte[capacity];
118             if (bytes != null) {
119                 copyBytes(bytes, 0, newbytes, 0, size);
120             }
121             bytes = newbytes;
122         }
123         return this;
124     }
125 
126     /**
127      * Set the internal byte array from offset 0 to (limit - start) with the
128      * contents of src from offset start to limit. If the byte array is null or its length is less than capacity, a new
129      * byte array of length (limit - start) will be allocated.
130      * This resets the size of the internal byte array to (limit - start).
131      * @param src source byte array to copy from
132      * @param start start offset of src to copy from
133      * @param limit end + 1 offset of src to copy from
134      * @return this ByteArrayWrapper
135      * @stable ICU 3.2
136      */
set(byte[] src, int start, int limit)137     public final ByteArrayWrapper set(byte[] src, int start, int limit)
138     {
139         size = 0;
140         append(src, start, limit);
141         return this;
142     }
143 
144     /*
145     public final ByteArrayWrapper get(byte[] target, int start, int limit)
146     {
147         int len = limit - start;
148         if (len > size) throw new IllegalArgumentException("limit too long");
149         copyBytes(bytes, 0, target, start, len);
150         return this;
151     }
152     */
153 
154     /**
155      * Appends the internal byte array from offset size with the
156      * contents of src from offset start to limit. This increases the size of
157      * the internal byte array to (size + limit - start).
158      * @param src source byte array to copy from
159      * @param start start offset of src to copy from
160      * @param limit end + 1 offset of src to copy from
161      * @return this ByteArrayWrapper
162      * @stable ICU 3.2
163      */
append(byte[] src, int start, int limit)164     public final ByteArrayWrapper append(byte[] src, int start, int limit)
165     {
166         int len = limit - start;
167         ensureCapacity(size + len);
168         copyBytes(src, start, bytes, size, len);
169         size += len;
170         return this;
171     }
172 
173     /*
174     public final ByteArrayWrapper append(ByteArrayWrapper other)
175     {
176         return append(other.bytes, 0, other.size);
177     }
178     */
179 
180     /**
181      * Releases the internal byte array to the caller, resets the internal
182      * byte array to null and its size to 0.
183      * @return internal byte array.
184      * @stable ICU 2.8
185      */
releaseBytes()186     public final byte[] releaseBytes()
187     {
188         byte result[] = bytes;
189         bytes = null;
190         size = 0;
191         return result;
192     }
193 
194     // Boilerplate ----------------------------------------------------
195 
196     /**
197      * Returns string value for debugging
198      * @stable ICU 2.8
199      */
200     @Override
toString()201     public String toString() {
202         StringBuilder result = new StringBuilder();
203         for (int i = 0; i < size; ++i) {
204             if (i != 0) result.append(" ");
205             result.append(Utility.hex(bytes[i]&0xFF,2));
206         }
207         return result.toString();
208     }
209 
210     /**
211      * Return true if the bytes in each wrapper are equal.
212      * @param other the object to compare to.
213      * @return true if the two objects are equal.
214      * @stable ICU 2.8
215      */
216     @Override
equals(Object other)217     public boolean equals(Object other) {
218         if (this == other) return true;
219         if (other == null) return false;
220         try {
221             ByteArrayWrapper that = (ByteArrayWrapper)other;
222             if (size != that.size) return false;
223             for (int i = 0; i < size; ++i) {
224                 if (bytes[i] != that.bytes[i]) return false;
225             }
226             return true;
227         }
228         catch (ClassCastException e) {
229         }
230         return false;
231     }
232 
233     /**
234      * Return the hashcode.
235      * @return the hashcode.
236      * @stable ICU 2.8
237      */
238     @Override
hashCode()239     public int hashCode() {
240         int result = bytes.length;
241         for (int i = 0; i < size; ++i) {
242             result = 37*result + bytes[i];
243         }
244         return result;
245     }
246 
247     /**
248      * Compare this object to another ByteArrayWrapper, which must not be null.
249      * @param other the object to compare to.
250      * @return a value &lt;0, 0, or &gt;0 as this compares less than, equal to, or
251      * greater than other.
252      * @throws ClassCastException if the other object is not a ByteArrayWrapper
253      * @stable ICU 4.4
254      */
255     @Override
compareTo(ByteArrayWrapper other)256     public int compareTo(ByteArrayWrapper other) {
257         if (this == other) return 0;
258         int minSize = size < other.size ? size : other.size;
259         for (int i = 0; i < minSize; ++i) {
260             if (bytes[i] != other.bytes[i]) {
261                 return (bytes[i] & 0xFF) - (other.bytes[i] & 0xFF);
262             }
263         }
264         return size - other.size;
265     }
266 
267     // private methods -----------------------------------------------------
268 
269     /**
270      * Copies the contents of src byte array from offset srcoff to the
271      * target of tgt byte array at the offset tgtoff.
272      * @param src source byte array to copy from
273      * @param srcoff start offset of src to copy from
274      * @param tgt target byte array to copy to
275      * @param tgtoff start offset of tgt to copy to
276      * @param length size of contents to copy
277      */
278     private static final void copyBytes(byte[] src, int srcoff, byte[] tgt,
279                                        int tgtoff, int length) {
280         if (length < 64) {
281             for (int i = srcoff, n = tgtoff; -- length >= 0; ++ i, ++ n) {
282                 tgt[n] = src[i];
283             }
284         }
285         else {
286             System.arraycopy(src, srcoff, tgt, tgtoff, length);
287         }
288     }
289 }
290