Home | History | Annotate | Download | only in util
      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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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 3.2
    199      */
    200     public String toString() {
    201         StringBuilder result = new StringBuilder();
    202         for (int i = 0; i < size; ++i) {
    203             if (i != 0) result.append(" ");
    204             result.append(Utility.hex(bytes[i]&0xFF,2));
    205         }
    206         return result.toString();
    207     }
    208 
    209     /**
    210      * Return true if the bytes in each wrapper are equal.
    211      * @param other the object to compare to.
    212      * @return true if the two objects are equal.
    213      * @stable ICU 3.2
    214      */
    215     public boolean equals(Object other) {
    216         if (this == other) return true;
    217         if (other == null) return false;
    218         try {
    219             ByteArrayWrapper that = (ByteArrayWrapper)other;
    220             if (size != that.size) return false;
    221             for (int i = 0; i < size; ++i) {
    222                 if (bytes[i] != that.bytes[i]) return false;
    223             }
    224             return true;
    225         }
    226         catch (ClassCastException e) {
    227         }
    228         return false;
    229     }
    230 
    231     /**
    232      * Return the hashcode.
    233      * @return the hashcode.
    234      * @stable ICU 3.2
    235      */
    236     public int hashCode() {
    237         int result = bytes.length;
    238         for (int i = 0; i < size; ++i) {
    239             result = 37*result + bytes[i];
    240         }
    241         return result;
    242     }
    243 
    244     /**
    245      * Compare this object to another ByteArrayWrapper, which must not be null.
    246      * @param other the object to compare to.
    247      * @return a value &lt;0, 0, or &gt;0 as this compares less than, equal to, or
    248      * greater than other.
    249      * @throws ClassCastException if the other object is not a ByteArrayWrapper
    250      * @stable ICU 4.4
    251      */
    252     public int compareTo(ByteArrayWrapper other) {
    253         if (this == other) return 0;
    254         int minSize = size < other.size ? size : other.size;
    255         for (int i = 0; i < minSize; ++i) {
    256             if (bytes[i] != other.bytes[i]) {
    257                 return (bytes[i] & 0xFF) - (other.bytes[i] & 0xFF);
    258             }
    259         }
    260         return size - other.size;
    261     }
    262 
    263     // private methods -----------------------------------------------------
    264 
    265     /**
    266      * Copies the contents of src byte array from offset srcoff to the
    267      * target of tgt byte array at the offset tgtoff.
    268      * @param src source byte array to copy from
    269      * @param srcoff start offset of src to copy from
    270      * @param tgt target byte array to copy to
    271      * @param tgtoff start offset of tgt to copy to
    272      * @param length size of contents to copy
    273      */
    274     private static final void copyBytes(byte[] src, int srcoff, byte[] tgt,
    275                                        int tgtoff, int length) {
    276         if (length < 64) {
    277             for (int i = srcoff, n = tgtoff; -- length >= 0; ++ i, ++ n) {
    278                 tgt[n] = src[i];
    279             }
    280         }
    281         else {
    282             System.arraycopy(src, srcoff, tgt, tgtoff, length);
    283         }
    284     }
    285 }
    286