/* * Copyright 2015 Christian Basler * * 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 ch.dissem.bitmessage.utils; /** * A helper class for working with byte arrays interpreted as unsigned big endian integers. * This is one part due to the fact that Java doesn't support unsigned numbers, and another * part so we don't have to convert between byte arrays and numbers in time critical * situations. */ public class Bytes { public static void inc(byte[] nonce) { for (int i = nonce.length - 1; i >= 0; i--) { nonce[i]++; if (nonce[i] != 0) break; } } /** * Increases nonce by value, which is used as an unsigned byte value. * * @param nonce an unsigned number * @param value to be added to nonce */ public static void inc(byte[] nonce, byte value) { int i = nonce.length - 1; nonce[i] += value; if (value > 0 && (nonce[i] < 0 || nonce[i] >= value)) return; if (value < 0 && (nonce[i] < 0 && nonce[i] >= value)) return; for (i = i - 1; i >= 0; i--) { nonce[i]++; if (nonce[i] != 0) break; } } /** * @return true if a < b. */ public static boolean lt(byte[] a, byte[] b) { byte[] max = (a.length > b.length ? a : b); byte[] min = (max == a ? b : a); int diff = max.length - min.length; for (int i = 0; i < max.length - min.length; i++) { if (max[i] != 0) return a != max; } for (int i = diff; i < max.length; i++) { if (max[i] != min[i - diff]) { return lt(max[i], min[i - diff]) == (a == max); } } return false; } /** * @return true if a < b, where the first [size] bytes are used as the numbers to check. */ public static boolean lt(byte[] a, byte[] b, int size) { for (int i = 0; i < size; i++) { if (a[i] != b[i]) { return lt(a[i], b[i]); } } return false; } private static boolean lt(byte a, byte b) { if (a < 0) return b < 0 && a < b; if (b < 0) return a >= 0 || a < b; return a < b; // This would be easier to understand, but is (slightly) slower: // return (a & 0xff) < (b & 0xff); } /** * @return a new byte array of length, left-padded with '0'. */ public static byte[] expand(byte[] source, int size) { byte[] result = new byte[size]; System.arraycopy(source, 0, result, size - source.length, source.length); return result; } /** * @return a new byte array containing the first size bytes of the given array. */ public static byte[] truncate(byte[] source, int size) { byte[] result = new byte[size]; System.arraycopy(source, 0, result, 0, size); return result; } /** * @return the byte array that hex represents. This is meant for test use and should be rewritten if used in * production code. */ public static byte[] fromHex(String hex) { if (hex.length() % 2 != 0) throw new IllegalArgumentException("expected even number of characters"); byte[] result = new byte[hex.length() / 2]; for (int i = 0; i < result.length; i++) { result[i] = (byte) (hexValue(hex.charAt(i * 2)) * 16); result[i] += hexValue(hex.charAt(i * 2 + 1)); } return result; } private static int hexValue(char c) { if (c >= '0' && c <= '9') { return c - '0'; } if (c >= 'a' && c <= 'f') { return 10 + c - 'a'; } if (c >= 'A' && c <= 'F') { return 10 + c - 'A'; } throw new IllegalArgumentException("'" + c + "' is not a valid hex value"); } /** * @return the number of leading '0' of a byte array. */ public static int numberOfLeadingZeros(byte[] bytes) { int i; for (i = 0; i < bytes.length; i++) { if (bytes[i] != 0) return i; } return i; } }