blob: 72a2998ff508e355237eea13d62cdda7613736e9 [file] [log] [blame]
/**
*******************************************************************************
* Copyright (C) 1996-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.util;
import java.nio.ByteBuffer;
import com.ibm.icu.impl.Utility;
/**
* <p>
* A simple utility class to wrap a byte array.
* </p>
* <p>
* Generally passed as an argument object into a method. The method takes
* responsibility of writing into the internal byte array and increasing its
* size when necessary.
* </p>
* @author syn wee
* @stable ICU 2.8
*/
public class ByteArrayWrapper implements Comparable<ByteArrayWrapper>
{
// public data member ------------------------------------------------
/**
* Internal byte array.
* @stable ICU 2.8
*/
public byte[] bytes;
/**
* Size of the internal byte array used.
* Different from bytes.length, size will be &lt;= bytes.length.
* Semantics of size is similar to java.util.Vector.size().
* @stable ICU 2.8
*/
public int size;
// public constructor ------------------------------------------------
/**
* Construct a new ByteArrayWrapper with no data.
* @stable ICU 2.8
*/
public ByteArrayWrapper() {
// leave bytes null, don't allocate twice
}
/**
* Construct a new ByteArrayWrapper from a byte array and size
* @param bytesToAdopt the byte array to adopt
* @param size the length of valid data in the byte array
* @throws IndexOutOfBoundsException if bytesToAdopt == null and size != 0, or
* size < 0, or size > bytesToAdopt.length.
* @stable ICU 3.2
*/
public ByteArrayWrapper(byte[] bytesToAdopt, int size) {
if ((bytesToAdopt == null && size != 0) || size < 0 || size > bytesToAdopt.length) {
throw new IndexOutOfBoundsException("illegal size: " + size);
}
this.bytes = bytesToAdopt;
this.size = size;
}
/**
* Construct a new ByteArrayWrapper from the contents of a ByteBuffer.
* @param source the ByteBuffer from which to get the data.
* @stable ICU 3.2
*/
public ByteArrayWrapper(ByteBuffer source) {
size = source.limit();
bytes = new byte[size];
source.get(bytes,0,size);
}
/**
* Create from ByteBuffer
* @param byteBuffer
public ByteArrayWrapper(ByteArrayWrapper source) {
size = source.size;
bytes = new byte[size];
copyBytes(source.bytes, 0, bytes, 0, size);
}
*/
/**
* create from byte buffer
* @param src
* @param start
* @param limit
public ByteArrayWrapper(byte[] src, int start, int limit) {
size = limit - start;
bytes = new byte[size];
copyBytes(src, start, bytes, 0, size);
}
*/
// public methods ----------------------------------------------------
/**
* Ensure that the internal byte array is at least of length capacity.
* If the byte array is null or its length is less than capacity, a new
* byte array of length capacity will be allocated.
* The contents of the array (between 0 and size) remain unchanged.
* @param capacity minimum length of internal byte array.
* @return this ByteArrayWrapper
* @stable ICU 3.2
*/
public ByteArrayWrapper ensureCapacity(int capacity)
{
if (bytes == null || bytes.length < capacity) {
byte[] newbytes = new byte[capacity];
copyBytes(bytes, 0, newbytes, 0, size);
bytes = newbytes;
}
return this;
}
/**
* Set the internal byte array from offset 0 to (limit - start) with the
* contents of src from offset start to limit. If the byte array is null or its length is less than capacity, a new
* byte array of length (limit - start) will be allocated.
* This resets the size of the internal byte array to (limit - start).
* @param src source byte array to copy from
* @param start start offset of src to copy from
* @param limit end + 1 offset of src to copy from
* @return this ByteArrayWrapper
* @stable ICU 3.2
*/
public final ByteArrayWrapper set(byte[] src, int start, int limit)
{
size = 0;
append(src, start, limit);
return this;
}
/*
public final ByteArrayWrapper get(byte[] target, int start, int limit)
{
int len = limit - start;
if (len > size) throw new IllegalArgumentException("limit too long");
copyBytes(bytes, 0, target, start, len);
return this;
}
*/
/**
* Appends the internal byte array from offset size with the
* contents of src from offset start to limit. This increases the size of
* the internal byte array to (size + limit - start).
* @param src source byte array to copy from
* @param start start offset of src to copy from
* @param limit end + 1 offset of src to copy from
* @return this ByteArrayWrapper
* @stable ICU 3.2
*/
public final ByteArrayWrapper append(byte[] src, int start, int limit)
{
int len = limit - start;
ensureCapacity(size + len);
copyBytes(src, start, bytes, size, len);
size += len;
return this;
}
/*
public final ByteArrayWrapper append(ByteArrayWrapper other)
{
return append(other.bytes, 0, other.size);
}
*/
/**
* Releases the internal byte array to the caller, resets the internal
* byte array to null and its size to 0.
* @return internal byte array.
* @stable ICU 2.8
*/
public final byte[] releaseBytes()
{
byte result[] = bytes;
bytes = null;
size = 0;
return result;
}
// Boilerplate ----------------------------------------------------
/**
* Returns string value for debugging
* @stable ICU 3.2
*/
public String toString() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < size; ++i) {
if (i != 0) result.append(" ");
result.append(Utility.hex(bytes[i]&0xFF,2));
}
return result.toString();
}
/**
* Return true if the bytes in each wrapper are equal.
* @param other the object to compare to.
* @return true if the two objects are equal.
* @stable ICU 3.2
*/
public boolean equals(Object other) {
if (this == other) return true;
if (other == null) return false;
try {
ByteArrayWrapper that = (ByteArrayWrapper)other;
if (size != that.size) return false;
for (int i = 0; i < size; ++i) {
if (bytes[i] != that.bytes[i]) return false;
}
return true;
}
catch (ClassCastException e) {
}
return false;
}
/**
* Return the hashcode.
* @return the hashcode.
* @stable ICU 3.2
*/
public int hashCode() {
int result = bytes.length;
for (int i = 0; i < size; ++i) {
result = 37*result + bytes[i];
}
return result;
}
/**
* Compare this object to another ByteArrayWrapper, which must not be null.
* @param other the object to compare to.
* @return a value <0, 0, or >0 as this compares less than, equal to, or
* greater than other.
* @throws ClassCastException if the other object is not a ByteArrayWrapper
* @stable ICU 4.4
*/
public int compareTo(ByteArrayWrapper other) {
if (this == other) return 0;
int minSize = size < other.size ? size : other.size;
for (int i = 0; i < minSize; ++i) {
if (bytes[i] != other.bytes[i]) {
return (bytes[i] & 0xFF) - (other.bytes[i] & 0xFF);
}
}
return size - other.size;
}
// private methods -----------------------------------------------------
/**
* Copies the contents of src byte array from offset srcoff to the
* target of tgt byte array at the offset tgtoff.
* @param src source byte array to copy from
* @param srcoff start offset of src to copy from
* @param tgt target byte array to copy to
* @param tgtoff start offset of tgt to copy to
* @param length size of contents to copy
*/
private static final void copyBytes(byte[] src, int srcoff, byte[] tgt,
int tgtoff, int length) {
if (length < 64) {
for (int i = srcoff, n = tgtoff; -- length >= 0; ++ i, ++ n) {
tgt[n] = src[i];
}
}
else {
System.arraycopy(src, srcoff, tgt, tgtoff, length);
}
}
}