/* * Created by Angel Leon (@gubatron), Alden Torres (aldenml) * Copyright (c) 2011, 2012, FrostWire(TM). All rights reserved. * * 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 3 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, see <http://www.gnu.org/licenses/>. */ package com.frostwire.android.util; import java.util.Random; /** * @author gubatron * @author aldenml * */ public final class ByteUtils { private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private ByteUtils() { } /** * Given an int, returns the int as a 2 byte array of unsigned bytes. * * @param v the value to convert * @return a byte array with two elements */ public static byte[] smallIntToByteArray(int v) { if (v > 65535) { throw new IllegalArgumentException("value is too big"); } return new byte[] { (byte) ((v >>> 8) & 0xFF), (byte) ((v >>> 0) & 0xFF) }; } /** * Used to express smaller sizes (2 bytes), since UDP Packets can be of up * to 65535 (including headers). Our package sizes should not be longer than * 65,400 bytes. * * @param arr array of at least 2 bytes * @param offset offset that leaves at least 2 bytes forward * @return the small int value */ public static int byteArrayToSmallInt(byte[] arr, int offset) { if (arr == null || arr.length - offset < 2) { throw new IllegalArgumentException("Invalid arguments"); } return ((arr[offset] & 0xFF) << 8) + (arr[1 + offset] & 0xFF); } // 3 bytes (16,777,215 - 16 MB) public static byte[] smallIntToTripleByteArray(int v) { if (v > 16777215) { throw new IllegalArgumentException("value is too big"); } return new byte[] { (byte) ((v >>> 16) & 0xFF), (byte) ((v >>> 8) & 0xFF), (byte) ((v >>> 0) & 0xFF) }; } /** * Used to express numbers up to 16,777,215. * * @param arr - array of at least 3 bytes * @param i - offset that leaves at least 3 bytes forward * @return */ public static int tripleByteArrayToSmallInt(byte[] arr, int offset) { if (arr == null || arr.length - offset < 2) { throw new IllegalArgumentException("Invalid arguments"); } return ((arr[offset] & 0xFF) << 16) + ((arr[1 + offset] & 0xFF) << 8) + (arr[2 + offset] & 0xFF); } /** * Returns a 3 byte array checksum number calculated on the given array. * * The checksum algorithm is very simple. We add up every N bytes * in the array, and return this number as a 3 byte array. * * Currently we're jumping 16 bytes at the time. This takes up to 1 millisecond. * A 13mb made of 200 byte arrays of 65535 bytes parts can be checksumed * in 245ms on a Nexus One. * * @param arr - An array of no more than 65535 bytes. * @return the checksum array of size three */ public static byte[] getByteArrayChecksum(byte[] arr) { if (arr.length > 65535) { throw new IllegalArgumentException("Byte array is too long"); } // max UDP packets are 65535 bytes long // even if we used all of those bytes, the max number added would be int result = 0; int step = arr.length > 100 ? 16 : 1; for (int i = 0; i < arr.length; i += step) { result += (arr[i] & 0xFF); } return smallIntToTripleByteArray(result); } /** * Returns a new byte array: c = a + b. * * The array a will be towards the 0 index, the array b right after. * * c.length = a.length + b.length * * @param a the first array * @param b the second array * @return the final array */ public static byte[] appendByteArrays(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; } public static int randomInt(int min, int max) { Random random = new Random(System.currentTimeMillis()); return min + random.nextInt(max - min); } public static byte[] decodeHex(String str) { str = str.toLowerCase(); int len = str.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16)); } return data; } public static String encodeHex(byte[] data) { int l = data.length; char[] out = new char[l << 1]; // two characters form the hex value. for (int i = 0, j = 0; i < l; i++) { out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; out[j++] = DIGITS[0x0F & data[i]]; } return new String(out); } }