| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.rocketmq.remoting.internal; |
| |
| /** |
| * Copy from Bouncy Castle Crypto APIs |
| * |
| * This class is a utility class for manipulating byte arrays. |
| */ |
| public final class ByteUtils { |
| |
| private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; |
| |
| /** |
| * Default constructor (private) |
| */ |
| private ByteUtils() { |
| // empty |
| } |
| |
| /** |
| * Compare two two-dimensional byte arrays. No null checks are performed. |
| * |
| * @param left the first byte array |
| * @param right the second byte array |
| * @return the result of the comparison |
| */ |
| public static boolean equals(byte[][] left, byte[][] right) { |
| if (left.length != right.length) { |
| return false; |
| } |
| |
| boolean result = true; |
| for (int i = left.length - 1; i >= 0; i--) { |
| result &= ByteUtils.equals(left[i], right[i]); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Compare two byte arrays (perform null checks beforehand). |
| * |
| * @param left the first byte array |
| * @param right the second byte array |
| * @return the result of the comparison |
| */ |
| public static boolean equals(byte[] left, byte[] right) { |
| if (left == null) { |
| return right == null; |
| } |
| if (right == null) { |
| return false; |
| } |
| |
| if (left.length != right.length) { |
| return false; |
| } |
| boolean result = true; |
| for (int i = left.length - 1; i >= 0; i--) { |
| result &= left[i] == right[i]; |
| } |
| return result; |
| } |
| |
| /** |
| * Compare two three-dimensional byte arrays. No null checks are performed. |
| * |
| * @param left the first byte array |
| * @param right the second byte array |
| * @return the result of the comparison |
| */ |
| public static boolean equals(byte[][][] left, byte[][][] right) { |
| if (left.length != right.length) { |
| return false; |
| } |
| |
| boolean result = true; |
| for (int i = left.length - 1; i >= 0; i--) { |
| if (left[i].length != right[i].length) { |
| return false; |
| } |
| for (int j = left[i].length - 1; j >= 0; j--) { |
| result &= ByteUtils.equals(left[i][j], right[i][j]); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Computes a hashcode based on the contents of a three-dimensional byte |
| * array rather than its identity. |
| * |
| * @param array the array to compute the hashcode of |
| * @return the hashcode |
| */ |
| public static int deepHashCode(byte[][][] array) { |
| int result = 1; |
| for (int i = 0; i < array.length; i++) { |
| result = 31 * result + deepHashCode(array[i]); |
| } |
| return result; |
| } |
| |
| /** |
| * Computes a hashcode based on the contents of a two-dimensional byte array |
| * rather than its identity. |
| * |
| * @param array the array to compute the hashcode of |
| * @return the hashcode |
| */ |
| public static int deepHashCode(byte[][] array) { |
| int result = 1; |
| for (int i = 0; i < array.length; i++) { |
| result = 31 * result + deepHashCode(array[i]); |
| } |
| return result; |
| } |
| |
| /** |
| * Computes a hashcode based on the contents of a one-dimensional byte array |
| * rather than its identity. |
| * |
| * @param array the array to compute the hashcode of |
| * @return the hashcode |
| */ |
| public static int deepHashCode(byte[] array) { |
| int result = 1; |
| for (int i = 0; i < array.length; i++) { |
| result = 31 * result + array[i]; |
| } |
| return result; |
| } |
| |
| /** |
| * Return a clone of the given byte array (performs null check beforehand). |
| * |
| * @param array the array to clone |
| * @return the clone of the given array, or <tt>null</tt> if the array is |
| * <tt>null</tt> |
| */ |
| public static byte[] clone(byte[] array) { |
| if (array == null) { |
| return null; |
| } |
| byte[] result = new byte[array.length]; |
| System.arraycopy(array, 0, result, 0, array.length); |
| return result; |
| } |
| |
| /** |
| * Convert a string containing hexadecimal characters to a byte-array. |
| * |
| * @param s a hex string |
| * @return a byte array with the corresponding value |
| */ |
| public static byte[] fromHexString(String s) { |
| char[] rawChars = s.toUpperCase().toCharArray(); |
| |
| int hexChars = 0; |
| for (int i = 0; i < rawChars.length; i++) { |
| if ((rawChars[i] >= '0' && rawChars[i] <= '9') |
| || (rawChars[i] >= 'A' && rawChars[i] <= 'F')) { |
| hexChars++; |
| } |
| } |
| |
| byte[] byteString = new byte[(hexChars + 1) >> 1]; |
| |
| int pos = hexChars & 1; |
| |
| for (int i = 0; i < rawChars.length; i++) { |
| if (rawChars[i] >= '0' && rawChars[i] <= '9') { |
| byteString[pos >> 1] <<= 4; |
| byteString[pos >> 1] |= rawChars[i] - '0'; |
| } else if (rawChars[i] >= 'A' && rawChars[i] <= 'F') { |
| byteString[pos >> 1] <<= 4; |
| byteString[pos >> 1] |= rawChars[i] - 'A' + 10; |
| } else { |
| continue; |
| } |
| pos++; |
| } |
| |
| return byteString; |
| } |
| |
| /** |
| * Convert a byte array to the corresponding hexstring. |
| * |
| * @param input the byte array to be converted |
| * @return the corresponding hexstring |
| */ |
| public static String toHexString(byte[] input) { |
| String result = ""; |
| for (int i = 0; i < input.length; i++) { |
| result += HEX_CHARS[(input[i] >>> 4) & 0x0f]; |
| result += HEX_CHARS[(input[i]) & 0x0f]; |
| } |
| return result; |
| } |
| |
| /** |
| * Convert a byte array to the corresponding hex string. |
| * |
| * @param input the byte array to be converted |
| * @param prefix the prefix to put at the beginning of the hex string |
| * @param seperator a separator string |
| * @return the corresponding hex string |
| */ |
| public static String toHexString(byte[] input, String prefix, |
| String seperator) { |
| String result = new String(prefix); |
| for (int i = 0; i < input.length; i++) { |
| result += HEX_CHARS[(input[i] >>> 4) & 0x0f]; |
| result += HEX_CHARS[(input[i]) & 0x0f]; |
| if (i < input.length - 1) { |
| result += seperator; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Convert a byte array to the corresponding bit string. |
| * |
| * @param input the byte array to be converted |
| * @return the corresponding bit string |
| */ |
| public static String toBinaryString(byte[] input) { |
| String result = ""; |
| int i; |
| for (i = 0; i < input.length; i++) { |
| int e = input[i]; |
| for (int ii = 0; ii < 8; ii++) { |
| int b = (e >>> ii) & 1; |
| result += b; |
| } |
| if (i != input.length - 1) { |
| result += " "; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Compute the bitwise XOR of two arrays of bytes. The arrays have to be of |
| * same length. No length checking is performed. |
| * |
| * @param x1 the first array |
| * @param x2 the second array |
| * @return x1 XOR x2 |
| */ |
| public static byte[] xor(byte[] x1, byte[] x2) { |
| byte[] out = new byte[x1.length]; |
| |
| for (int i = x1.length - 1; i >= 0; i--) { |
| out[i] = (byte) (x1[i] ^ x2[i]); |
| } |
| return out; |
| } |
| |
| /** |
| * Concatenate two byte arrays. No null checks are performed. |
| * |
| * @param x1 the first array |
| * @param x2 the second array |
| * @return (x2 | | x1) (little-endian order, i.e. x1 is at lower memory |
| * addresses) |
| */ |
| public static byte[] concatenate(byte[] x1, byte[] x2) { |
| byte[] result = new byte[x1.length + x2.length]; |
| |
| System.arraycopy(x1, 0, result, 0, x1.length); |
| System.arraycopy(x2, 0, result, x1.length, x2.length); |
| |
| return result; |
| } |
| |
| /** |
| * Convert a 2-dimensional byte array into a 1-dimensional byte array by |
| * concatenating all entries. |
| * |
| * @param array a 2-dimensional byte array |
| * @return the concatenated input array |
| */ |
| public static byte[] concatenate(byte[][] array) { |
| int rowLength = array[0].length; |
| byte[] result = new byte[array.length * rowLength]; |
| int index = 0; |
| for (int i = 0; i < array.length; i++) { |
| System.arraycopy(array[i], 0, result, index, rowLength); |
| index += rowLength; |
| } |
| return result; |
| } |
| |
| /** |
| * Split a byte array <tt>input</tt> into two arrays at <tt>index</tt>, |
| * i.e. the first array will have the lower <tt>index</tt> bytes, the |
| * second one the higher <tt>input.length - index</tt> bytes. |
| * |
| * @param input the byte array to be split |
| * @param index the index where the byte array is split |
| * @return the splitted input array as an array of two byte arrays |
| * @throws ArrayIndexOutOfBoundsException if <tt>index</tt> is out of bounds |
| */ |
| public static byte[][] split(byte[] input, int index) |
| throws ArrayIndexOutOfBoundsException { |
| if (index > input.length) { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| byte[][] result = new byte[2][]; |
| result[0] = new byte[index]; |
| result[1] = new byte[input.length - index]; |
| System.arraycopy(input, 0, result[0], 0, index); |
| System.arraycopy(input, index, result[1], 0, input.length - index); |
| return result; |
| } |
| |
| /** |
| * Generate a subarray of a given byte array. |
| * |
| * @param input the input byte array |
| * @param start the start index |
| * @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> to |
| * the end of the array |
| */ |
| public static byte[] subArray(byte[] input, int start) { |
| return subArray(input, start, input.length); |
| } |
| |
| /** |
| * Generate a subarray of a given byte array. |
| * |
| * @param input the input byte array |
| * @param start the start index |
| * @param end the end index |
| * @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> |
| * (inclusively) to <tt>end</tt> (exclusively) |
| */ |
| public static byte[] subArray(byte[] input, int start, int end) { |
| byte[] result = new byte[end - start]; |
| System.arraycopy(input, start, result, 0, end - start); |
| return result; |
| } |
| |
| /** |
| * Rewrite a byte array as a char array |
| * |
| * @param input - |
| * the byte array |
| * @return char array |
| */ |
| public static char[] toCharArray(byte[] input) { |
| char[] result = new char[input.length]; |
| for (int i = 0; i < input.length; i++) { |
| result[i] = (char) input[i]; |
| } |
| return result; |
| } |
| |
| } |