package org.bitseal.util; import java.math.BigInteger; /** * This class provides some static methods for manipulating bytes and * byte arrays. * * @author Jonathan Coe */ public final class ByteUtils { private ByteUtils() { // The constructor of this class is private in order to prevent the class being instantiated } /** * Converts a byte[] of unsigned bytes in big-endian order to a short. * * @param bytes - A byte[] containing the bytes to convert. * * @return A short containing the equivalent signed value of the given bytes. */ public static short bytesToShort(byte[] bytes) { short s = 0; s |= (bytes[0] & 0xFF) << 8; s |= (bytes[1] & 0xFF); return s; } /** * Converts a byte[] of unsigned bytes in big-endian order to an int. * * @param bytes - A byte[] containing the bytes to convert. * * @return An int containing the equivalent signed value of the given bytes. */ public static int bytesToInt(byte[] bytes) { int i = 0; i |= (bytes[0] & 0xFF) << 24; i |= (bytes[1] & 0xFF) << 16; i |= (bytes[2] & 0xFF) << 8; i |= (bytes[3] & 0xFF); return i; } /** * Converts a byte[] of unsigned bytes in big-endian order to a long. * * @param bytes - A byte[] containing the bytes to convert. * * @return A long containing the equivalent signed value of the given bytes. */ public static long bytesToLong(byte[] bytes) { long l = 0; l |= (bytes[0] & 0xFFL) << 56; l |= (bytes[1] & 0xFFL) << 48; l |= (bytes[2] & 0xFFL) << 40; l |= (bytes[3] & 0xFFL) << 32; l |= (bytes[4] & 0xFFL) << 24; l |= (bytes[5] & 0xFFL) << 16; l |= (bytes[6] & 0xFFL) << 8; l |= (bytes[7] & 0xFFL); return l; } /** * Returns a byte array containing the bytes of the given short in big endian order. * * @param i - The short to convert. * * @return A byte array containing the 2 bytes of the given short in big endian order. */ public static byte[] shortToBytes(short i) { return new byte[] { (byte) (i >> 8), (byte) (i & 0xFF) }; } /** * Returns a byte array containing the bytes of the given integer in big endian order. * * @param i - The integer to convert. * * @return A byte array containing the 4 bytes of the given integer in big endian order. */ public static byte[] intToBytes(int i) { return new byte[] { (byte) (i >> 24), (byte) (i >> 16 & 0xFF), (byte) (i >> 8 & 0xFF), (byte) (i & 0xFF) }; } /** * Returns a byte array containing the bytes of the given long in big endian order. * * @param l - The long to convert * * @return A byte array containing the 8 bytes of the given long in big endian order. */ public static byte[] longToBytes(long l) { return new byte[] { (byte) (l >> 56), (byte) (l >> 48), (byte) (l >> 40), (byte) (l >> 32), (byte) (l >> 24), (byte) (l >> 16 & 0xFF), (byte) (l >> 8 & 0xFF), (byte) (l & 0xFF) }; } /** * Concatenates two byte arrays * * @param a - The first byte[] * @param b - The second byte[] * * @return A byte[] containing the combined data from a and b, in that order */ public static byte[] concatenateByteArrays (byte[] a, byte[] b) { byte[] c = new byte[a.length + b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } /** * Concatenates three byte arrays * * @param a - The first byte[] * @param b - The second byte[] * @param c - The third byte[] * * @return A byte[] containing the combined data from a, b, and c, in that order */ public static byte[] concatenateByteArrays (byte[] a, byte[] b, byte[] c) { byte[] d = new byte[a.length + b.length + c.length]; System.arraycopy(a, 0, d, 0, a.length); System.arraycopy(b, 0, d, a.length, b.length); System.arraycopy(c, 0, d, a.length + b.length, c.length); return d; } /** * Concatenates four byte arrays * * @param a - The first byte[] * @param b - The second byte[] * @param c - The third byte[] * @param d - The fourth byte[] * * @return A byte[] containing the combined data from a, b, c, and d, in that order */ public static byte[] concatenateByteArrays (byte[] a, byte[] b, byte[] c, byte[] d) { byte[] e = new byte[a.length + b.length + c.length + d.length]; System.arraycopy(a, 0, e, 0, a.length); System.arraycopy(b, 0, e, a.length, b.length); System.arraycopy(c, 0, e, a.length + b.length, c.length); System.arraycopy(d, 0, e, a.length + b.length + c.length, d.length); return e; } /** * Concatenates five byte arrays * * @param a - The first byte[] * @param b - The second byte[] * @param c - The third byte[] * @param d - The fourth byte[] * @param e - The fifth byte[] * * @return A byte[] containing the combined data from a, b, c, d, and e, in that order */ public static byte[] concatenateByteArrays (byte[] a, byte[] b, byte[] c, byte[] d, byte[] e) { byte[] f = new byte[a.length + b.length + c.length + d.length + e.length]; System.arraycopy(a, 0, f, 0, a.length); System.arraycopy(b, 0, f, a.length, b.length); System.arraycopy(c, 0, f, a.length + b.length, c.length); System.arraycopy(d, 0, f, a.length + b.length + c.length, d.length); System.arraycopy(e, 0, f, a.length + b.length + c.length + d.length, e.length); return f; } /** * Returns a positive BigInteger from the given bytes. (Big endian) * * @param data - A byte[] containing the data to convert * @param start - An int representing the position of the first byte to copy. * @param length - An int representing the number of bytes to process. * * @return A BigInteger created from the given bytes. */ public static BigInteger getUnsignedBigInteger(byte[] data, int start, int length) { if (length == 0) { return BigInteger.ZERO; } byte[] value = new byte[length + 1]; System.arraycopy(data, start, value, 1, length); return new BigInteger(value); } /** * Returns an unsigned byte[] representation of the given big integer. * * @param number - The BigInteger. Must be >= 0 * @param length - An int representing the maximum length * * @return A byte[] containing the last bytes of the given big integer, filled with zeros if necessary. */ public static byte[] getUnsignedBytes(BigInteger number, int length) { byte[] value = number.toByteArray(); if (value.length > length + 1) { throw new IllegalArgumentException ("The given BigInteger does not fit into a byte array with the given length: " + value.length + " > " + length); } byte[] result = new byte[length]; int i = value.length == length + 1 ? 1 : 0; for (; i < value.length; i++) { result[i + length - value.length] = value[i]; } return result; } /** * Removes a specified range of bytes from the middle of a byte[], then * returns the remaining bytes from the array. * * @param original - The original byte array * @param start - The starting index of the range of bytes to be removed * @param end - The end index of the range of bytes to be removed * * @return A byte[] containing the remaining bytes from the array */ public static byte[] removeBytesFromArray(byte[] original, int start, int end) { byte[] firstPart = ArrayCopier.copyOfRange(original, 0, start); byte[] secondPart = ArrayCopier.copyOfRange(original, end, original.length); return concatenateByteArrays(firstPart, secondPart); } /** * Strips any leading zero bytes from a given byte[]. * * @param input - The input byte[] * * @return A byte[] with any leading zeros removed */ public static byte[] stripLeadingZeros(byte[] input) { while (input[0] == (byte) 0) { input = ArrayCopier.copyOfRange(input, 1, input.length); } return input; } /** * Takes a byte[] and pads it with leading zeros until its total * length is equal to the 'finalLength' parameter. <br><br> * * If the length of the supplied byte[] is already equal to or greater * than the supplied 'finalLength' value then the byte[] will be returned unchanged. * * @param input - The byte[] to be padded with leading zeros * @param finalLength - The desired total length of the byte[] once it * has been padded with leading zeros * * @return The byte[] with leading zeros added */ public static byte[] padWithLeadingZeros(byte[] input, int finalLength) { while (input.length < finalLength) { byte[] zeroByte = new byte[]{0}; input = ByteUtils.concatenateByteArrays(zeroByte, input); } return input; } }