/*
* ByteUtils.java
*
* Created on April 17, 2007, 6:53 PM
*
* Description: Byte array utilities adapted from org.apache.commons.id.uuid.Bytes.
*
* Copyright (C) 2007 Stephen L. Reed.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.texai.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Comparator;
import java.util.UUID;
/**
*
* @author reed
*/
public final class ByteUtils {
/** the hex characters */
private static final byte[] HEX_CHARACTERS = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f'
};
/** <p>Hide constructor in utility class.</p>
*/
private ByteUtils() {
}
/** Returns the lower 8 bits of the given int as a byte.
*
* @param i the given int
* @return the lower 8 bits of the given int as a byte
*/
public static byte toUnsignedByte(final int i) {
return (byte) (i & 0x000000ff);
}
/** Serializes the given object into a byte array.
*
* @param obj the given object
* @return the serialized byte array
*/
public static byte[] serialize(final Serializable obj) {
//Preconditions
assert obj != null : "obj must not be null";
ObjectOutputStream objectOutputStream = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
objectOutputStream.close();
return byteArrayOutputStream.toByteArray();
} catch (IOException ex) {
throw new TexaiException(ex);
} finally {
try {
if (objectOutputStream != null) {
objectOutputStream.close();
}
} catch (IOException ex) {
throw new TexaiException(ex);
}
}
}
/** Deserializes the given byte array into an object.
*
* @param bytes the given byte array
* @return the deserialized object
*/
public static Serializable deserialize(final byte[] bytes) {
//Preconditions
assert bytes != null : "obj must not be null";
final InputStream inputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(inputStream);
return (Serializable) objectInputStream.readObject();
} catch (IOException | ClassNotFoundException ex) {
throw new TexaiException(ex);
} finally {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
} catch (IOException ex) {
throw new TexaiException(ex);
}
}
}
/** Returns the array of bytes resulting from a new UUID.
*
* @return the array of bytes resulting from a new UUID
*/
public static byte[] makeUUIDBytes() {
final UUID uuid = UUID.randomUUID();
return append(toBytes(uuid.getMostSignificantBits()), toBytes(uuid.getLeastSignificantBits()));
}
/** Returns true if the given byte array is all zeros.
*
* @param bytes the given byte array
* @return true if the given byte array is all zeros
*/
public static boolean isZero(final Byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
for (byte myByte : bytes) {
if (myByte != 0) {
return false;
}
}
return true;
}
/** Returns true if the given byte array is all zeros.
*
* @param bytes the given byte array
* @return true if the given byte array is all zeros
*/
public static boolean isZero(final byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
for (byte myByte : bytes) {
if (myByte != 0) {
return false;
}
}
return true;
}
/** Returns true if the given byte array is not all zeros.
*
* @param bytes the given byte array
* @return true if the given byte array is not all zeros
*/
public static boolean isNonZero(final Byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
for (byte myByte : bytes) {
if (myByte == 0) {
return false;
}
}
return true;
}
/** Returns true if the given byte array is not all zeros.
*
* @param bytes the given byte array
* @return true if the given byte array is not all zeros
*/
public static boolean isNonZero(final byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
for (byte myByte : bytes) {
if (myByte == 0) {
return false;
}
}
return true;
}
/** Returns an array of Byte objects for the given UUID.
*
* @param uuid the UUID
* @return an array of Byte objects for the given UUID
*/
public static Byte[] toByteObjectArray(final UUID uuid) {
//Preconditions
assert uuid != null : "uuid must not be null";
final byte[] byteArray = toBytes(uuid);
final Byte[] bytes = new Byte[byteArray.length];
for (int i = 0; i < byteArray.length; i++) {
bytes[i] = byteArray[i];
}
return bytes;
}
/** Returns an array of Byte objects for the given byte array.
*
* @param bytes the byte array
* @return an array of Byte objects for the given byte array
*/
public static Byte[] toByteObjectArray(final byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
final Byte[] byteObjectArray = new Byte[bytes.length];
for (int i = 0; i < bytes.length; i++) {
byteObjectArray[i] = bytes[i];
}
return byteObjectArray;
}
/** Returns an array of bytes for the given Byte object array.
*
* @param byteObjectArray the given Byte object array
* @return an array of bytes for the given Byte object array
*/
public static byte[] toByteArray(final Byte[] byteObjectArray) {
//Preconditions
assert byteObjectArray != null : "byteObjectArray must not be null";
final byte[] bytes = new byte[byteObjectArray.length];
for (int i = 0; i < byteObjectArray.length; i++) {
bytes[i] = byteObjectArray[i];
}
return bytes;
}
/** Appends two bytes array into one.
*
* @param bytes1 the first given byte array
* @param bytes2 the second given byte array
* @return the byte array resulting from appending the two given byte arrays
*/
public static byte[] append(final byte[] bytes1, final byte[] bytes2) {
//Preconditions
assert bytes1 != null : "bytes1 must not be null";
assert bytes2 != null : "bytes2 must not be null";
final byte[] bytes3 = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes3, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes3, bytes1.length, bytes2.length);
return bytes3;
}
/** Returns a 8-byte array built from a long.
*
* @param number the long number to convert
* @return a byte array
*/
public static byte[] toBytes(final long number) {
final ByteBuffer byteBuffer = ByteBuffer.allocate(8);
byteBuffer.putLong(number);
return byteBuffer.array();
}
/** Builds a long from first 8 bytes of the array.
*
* @param bytes the byte array to convert
* @return a long
*/
public static long toLong(final byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
assert bytes.length == 8 : "the byte array must be length 8";
return ((((long) bytes[7]) & 0xFF)
+ ((((long) bytes[6]) & 0xFF) << 8)
+ ((((long) bytes[5]) & 0xFF) << 16)
+ ((((long) bytes[4]) & 0xFF) << 24)
+ ((((long) bytes[3]) & 0xFF) << 32)
+ ((((long) bytes[2]) & 0xFF) << 40)
+ ((((long) bytes[1]) & 0xFF) << 48)
+ ((((long) bytes[0]) & 0xFF) << 56));
}
/** Returns a 4-byte array built from an int.
*
* @param number the int number to convert
* @return a byte array
*/
public static byte[] toBytes(final int number) {
final ByteBuffer byteBuffer = ByteBuffer.allocate(4);
byteBuffer.putInt(number);
return byteBuffer.array();
}
/** Returns the 16-byte array from the given UUID.
*
* @param uuid the given UUID
* @return the 16-byte array from the given UUID
*/
public static byte[] toBytes(final UUID uuid) {
//Preconditions
assert uuid != null : "uuid must not be null";
return append(toBytes(uuid.getMostSignificantBits()), toBytes(uuid.getLeastSignificantBits()));
}
/** Returns a hexadecimal string representation of the given byte array.
*
* @param bytes the given byte array
* @return a hexadecimal string representation of the given byte array
*/
public static String toHex(final byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
final int byteArray_len = bytes.length;
final StringBuilder stringBuilder = new StringBuilder(2 * byteArray_len);
for (int i = 0; i < byteArray_len; i++) {
final int value = bytes[i] & 0xff;
stringBuilder.append((char) HEX_CHARACTERS[value >> 4]);
stringBuilder.append((char) HEX_CHARACTERS[value & 0xf]);
}
return stringBuilder.toString();
}
/** Returns a string representation of the given byte.
*
*@param byte1 the given byte
* @return a string representation of the given byte
*/
public static String toHex(final Byte byte1) {
final int value = byte1 & 0xff;
final StringBuilder stringBuilder = new StringBuilder(2);
stringBuilder.append((char) HEX_CHARACTERS[value >> 4]);
stringBuilder.append((char) HEX_CHARACTERS[value & 0xf]);
return stringBuilder.toString();
}
/** Returns the integer represented by the given hex digit character.
*
* @param hexCharacter the given hex digit character
* @return the integer represented by the given hex digit character
*/
public static int fromHex(final char hexCharacter) {
final char lowerCaseHexCharacter = Character.toLowerCase(hexCharacter);
for (int i = 0; i < 16; i++) {
if (HEX_CHARACTERS[i] == lowerCaseHexCharacter) {
return i;
}
}
assert false : "invalid hex digit";
return -1;
}
/** Returns the byte represented by the two hex digits.
*
* @param string two hex digits
* @return the byte represented by the two hex digits
*/
public static Byte fromHex(final String string) {
//Preconditions
assert string != null && string.length() == 2 : "string must have length 2";
final char c0 = string.charAt(0);
final char c1 = string.charAt(1);
return (byte) (16 * fromHex(c0) + fromHex(c1));
}
/** Convert the byte array to an int. The array must be four or less in length.
*
* @param bytes The byte array
* @return the integer
*/
public static int byteArrayToInt(final byte[] bytes) {
//Preconditions
assert bytes != null : "bytes must not be null";
if (bytes.length > 4) {
throw new IllegalArgumentException("must be four or less bytes");
}
return byteArrayToInt(bytes, 0);
}
/** Convert the byte array to an int starting from the given offset, and continuing for up to four bytes.
*
* @param bytes The byte array
* @param offset The array offset
* @return the integer
*/
public static int byteArrayToInt(final byte[] bytes, final int offset) {
//Preconditions
assert bytes != null : "bytes must not be null";
assert offset >= 0 : "offset must not be negative";
final int length;
if ((bytes.length - offset) > 4) {
length = 4;
} else {
length = bytes.length - offset;
}
int value = 0;
for (int i = 0; i < length; i++) {
final int shift = (length - 1 - i) * 8;
value += (bytes[i + offset] & 0x000000FF) << shift;
}
return value;
}
/** Compares two byte arrays for equality.
*
* @param bytes1 the first given byte array
* @param bytes2 the second given byte array
* @return True if the arrays have identical contents.
*/
public static boolean areEqual(final byte[] bytes1, final byte[] bytes2) {
//Preconditions
assert bytes1 != null : "bytes1 must not be null";
assert bytes2 != null : "bytes2 must not be null";
final int aLength = bytes1.length;
if (aLength != bytes2.length) {
return false;
}
for (int i = 0; i < aLength; i++) {
if (bytes1[i] != bytes2[i]) {
return false;
}
}
return true;
}
/** Compares two byte arrays for equality.
*
* @param bytes1 the first given byte array
* @param bytes2 the second given byte array
* @return True if the arrays have identical contents.
*/
public static boolean areEqual(final Byte[] bytes1, final Byte[] bytes2) {
//Preconditions
assert bytes1 != null : "bytes1 must not be null";
assert bytes2 != null : "bytes2 must not be null";
final int aLength = bytes1.length;
if (aLength != bytes2.length) {
return false;
}
for (int i = 0; i < aLength; i++) {
if (!bytes1[i].equals(bytes2[i])) {
return false;
}
}
return true;
}
/** <p>Compares two Byte arrays as specified by <code>Comparable</code> with respect to each byte as a signed integer.
*
* @param lhs - left hand value in the comparison operation.
* @param rhs - right hand value in the comparison operation.
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>.
*/
public static int compareTo(final Byte[] lhs, final Byte[] rhs) {
//Preconditions
assert lhs != null : "lhs must not be null";
assert rhs != null : "rhs must not be null";
return compareTo(toByteArray(lhs), toByteArray(rhs));
}
/** <p>Compares two byte arrays as specified by <code>Comparable</code> with respect to each byte as a signed integer.
*
* @param lhs - left hand value in the comparison operation.
* @param rhs - right hand value in the comparison operation.
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>.
*/
public static int compareTo(final byte[] lhs, final byte[] rhs) {
//Preconditions
assert lhs != null : "lhs must not be null";
assert rhs != null : "rhs must not be null";
if (lhs == rhs) {
return 0;
}
if (lhs.length != rhs.length) {
return ((lhs.length < rhs.length) ? -1 : +1);
}
for (int i = 0; i < lhs.length; i++) {
if (lhs[i] < rhs[i]) {
return -1;
} else if (lhs[i] > rhs[i]) {
return 1;
}
}
return 0;
}
/** Provides a byte array comparator with respect to each byte as a signed integer. */
public static class ByteArrayComparator implements Comparator<Byte[]>, Serializable {
/** the serialization version ID */
static final long serialVersionUID = 1;
/** Constructs a new ByteArrayComparator instance. */
public ByteArrayComparator() {
}
/** Compares the two given byte arrays with respect to each byte as a signed integer.
*
* @param bytes1 the first given byte array
* @param bytes2 the second given byte array
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>
*/
@Override
public int compare(final Byte[] bytes1, final Byte[] bytes2) {
//Preconditions
assert bytes1 != null : "bytes1 must not be null";
assert bytes2 != null : "bytes2 must not be null";
return compareTo(toByteArray(bytes1), toByteArray(bytes2));
}
}
}