/*
* Copyright 2011 David Brazdil
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.ac.cam.db538.cryptosms.utils;
import java.nio.ByteBuffer;
import uk.ac.cam.db538.cryptosms.crypto.Encryption;
/*
* Class with lots of useful low-level methods
*/
public class LowLevel {
/**
* Expects four bytes and returns an unsigned integer stored in a long that's represented by the bytes.
*
* @param data the data
* @return the unsigned int
*/
public static long getUnsignedInt(byte[] data) {
return getUnsignedInt(data, 0);
}
/**
* Expects four bytes (in an array at specified offset) and returns an unsigned integer stored in a long that's represented by the bytes.
*
* @param data the data
* @param offset the offset
* @return the unsigned int
*/
public static long getUnsignedInt(byte[] data, int offset) {
if (offset > data.length - 4)
throw new IndexOutOfBoundsException();
long result = data[offset] & 0xFF;
result <<= 8;
result |= (data[offset + 1] & 0xFF);
result <<= 8;
result |= (data[offset + 2] & 0xFF);
result <<= 8;
result |= data[offset + 3] & 0xFF;
return result;
}
/**
* Expects eight bytes and returns a long that's represented by the bytes.
*
* @param data the data
* @return the long
*/
public static long getLong(byte[] data) {
long result = 0L;
for (int i = 0; i < 8; ++i) {
result <<= 8;
result |= (data[i] & 0xFF);
}
return result;
}
/**
* Expects two bytes and returns a short.
*
* @param data the data
* @return the unsigned short
*/
public static int getUnsignedShort(byte[] data) {
return getUnsignedShort(data, 0);
}
/**
* Expects two bytes and returns a short.
*
* @param data the data
* @param offset the offset
* @return the unsigned short
*/
public static int getUnsignedShort(byte[] data, int offset) {
if (offset > data.length - 2)
throw new IndexOutOfBoundsException();
int result = data[offset] & 0xFF;
result <<= 8;
result |= (data[offset + 1] & 0xFF);
return result;
}
/**
* Expects an unsigned integer stored in the 4 low bytes of a long and returns an array of 4 bytes that represent them.
*
* @param integer the integer
* @return the bytes unsigned int
*/
public static byte[] getBytesUnsignedInt(long integer) {
byte[] result = new byte[4];
result[0] = (byte) ((integer >> 24) & 0xFF);
result[1] = (byte) ((integer >> 16) & 0xFF);
result[2] = (byte) ((integer >> 8) & 0xFF);
result[3] = (byte) (integer & 0xFF);
return result;
}
/**
* Expects a short and returns an array of 2 bytes that represents it.
*
* @param integer the integer
* @return the bytes unsigned short
*/
public static byte[] getBytesUnsignedShort(int integer) {
byte[] result = new byte[2];
result[0] = (byte) ((integer >> 8) & 0xFF);
result[1] = (byte) (integer & 0xFF);
return result;
}
/**
* Takes a number (has to be between 0 and 255) and returns a byte that represents it.
*
* @param number the number
* @return the bytes unsigned byte
*/
public static byte getBytesUnsignedByte(int number) {
return (byte)(number & 0xFF);
}
/**
* Expects a long and returns a byte array of 8 elements with its big endian representation.
*
* @param number the number
* @return the bytes long
*/
public static byte[] getBytesLong(long number) {
byte[] result = new byte[8];
result[0] = (byte) ((number >> 56) & 0xFF);
result[1] = (byte) ((number >> 48) & 0xFF);
result[2] = (byte) ((number >> 40) & 0xFF);
result[3] = (byte) ((number >> 32) & 0xFF);
result[4] = (byte) ((number >> 24) & 0xFF);
result[5] = (byte) ((number >> 16) & 0xFF);
result[6] = (byte) ((number >> 8) & 0xFF);
result[7] = (byte) (number & 0xFF);
return result;
}
/**
* Takes a byte that is supposed to be unsigned and returns an int that represents that number.
*
* @param number the number
* @return the unsigned byte
*/
public static int getUnsignedByte(byte number) {
return number & 0xFF;
}
/**
* Inserts data into an array of specified length. Puts random data behind to fill the rest.
*
* @param data the data
* @param length the length
* @return the byte[]
*/
public static byte[] wrapData(byte[] data, int length) {
ByteBuffer buffer = ByteBuffer.allocate(length);
if (data.length >= length)
buffer.put(data, 0, length);
else {
buffer.put(data);
buffer.put(Encryption.getEncryption().generateRandomData(length - data.length));
}
return buffer.array();
}
/**
* Cuts out byte array from a bigger array.
*
* @param data the data
* @param offset the offset
* @param length the length
* @return the byte[]
*/
public static byte[] cutData(byte[] data, int offset, int length) {
if (length > 0) {
byte[] result = new byte[length];
System.arraycopy(data, offset, result, 0, length);
return result;
} else
return new byte[0];
}
/**
* Takes string containing HEX data and returns byte array that represents it.
*
* @param s the s
* @return the byte[]
*/
public static byte[] fromHex(String s) {
int len = s.length() / 2;
byte[] data = new byte[len];
for (int i = 0; i < len; ++i) {
data[i] = (byte) ((Character.digit(s.charAt(2 * i), 16) << 4)
+ Character.digit(s.charAt(2 * i + 1), 16));
}
return data;
}
private static char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
* Turns byte array into string containing HEX of all the bytes.
*
* @param data the data
* @return the string
*/
public static String toHex(byte[] data) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < data.length; ++i) {
builder.append(hexChars[(data[i] & 0xF0) >> 4]);
builder.append(hexChars[data[i] & 0x0F]);
}
return builder.toString();
}
/**
* Round up division.
*
* @param number the number
* @param divisor the divisor
* @return the int
*/
public static int roundUpDivision(int number, int divisor) {
if (number < divisor)
return 1;
else
return (number + divisor - 1) / divisor;
}
/**
* Closest greatest multiple.
*
* @param number the number
* @param multipleOf the multiple of
* @return the int
*/
public static int closestGreatestMultiple(int number, int multipleOf) {
return multipleOf * roundUpDivision(number, multipleOf);
}
}