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 <= 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 < 0, or size > 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 <0, 0, or >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