/* * Copyright (C) 2010-2012 The Async HBase Authors. All rights reserved. * This file is part of Async HBase. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the StumbleUpon nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package org.deephacks.confit.internal.hbase; /** * Helper functions to manipulate byte arrays. * * This is slightly modified version of the Bytes class * found in asynchbase. * * All credit goes to The Async HBase Authors. * * https://github.com/stumbleupon/asynchbase */ public class Bytes { Bytes() { // See BytesUtils. } // ------------------------------ // // Byte array conversion utilies. // // ------------------------------ // /** * Reads a big-endian 2-byte short from the begining of the given array. * @param b The array to read from. * @return A short integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static short getShort(final byte[] b) { return getShort(b, 0); } /** * Reads a big-endian 2-byte short from an offset in the given array. * @param b The array to read from. * @param offset The offset in the array to start reading from. * @return A short integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static short getShort(final byte[] b, final int offset) { return (short) (b[offset] << 8 | b[offset + 1] & 0xFF); } /** * Reads a big-endian 2-byte unsigned short from the begining of the * given array. * @param b The array to read from. * @return A positive short integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static int getUnsignedShort(final byte[] b) { return getUnsignedShort(b, 0); } /** * Reads a big-endian 2-byte unsigned short from an offset in the * given array. * @param b The array to read from. * @param offset The offset in the array to start reading from. * @return A positive short integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static int getUnsignedShort(final byte[] b, final int offset) { return getShort(b, offset) & 0x0000FFFF; } /** * Writes a big-endian 2-byte short at the begining of the given array. * @param b The array to write to. * @param n A short integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static void setShort(final byte[] b, final short n) { setShort(b, n, 0); } /** * Writes a big-endian 2-byte short at an offset in the given array. * @param b The array to write to. * @param offset The offset in the array to start writing at. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static void setShort(final byte[] b, final short n, final int offset) { b[offset + 0] = (byte) (n >>> 8); b[offset + 1] = (byte) (n >>> 0); } /** * Creates a new byte array containing a big-endian 2-byte short integer. * @param n A short integer. * @return A new byte array containing the given value. */ public static byte[] fromShort(final short n) { final byte[] b = new byte[2]; setShort(b, n); return b; } /** * Reads a big-endian 4-byte integer from the begining of the given array. * @param b The array to read from. * @return An integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static int getInt(final byte[] b) { return getInt(b, 0); } /** * Reads a big-endian 4-byte integer from an offset in the given array. * @param b The array to read from. * @param offset The offset in the array to start reading from. * @return An integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static int getInt(final byte[] b, final int offset) { return (b[offset + 0] & 0xFF) << 24 | (b[offset + 1] & 0xFF) << 16 | (b[offset + 2] & 0xFF) << 8 | (b[offset + 3] & 0xFF) << 0; } /** * Reads a big-endian 4-byte unsigned integer from the begining of the * given array. * @param b The array to read from. * @return A positive integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static long getUnsignedInt(final byte[] b) { return getUnsignedInt(b, 0); } /** * Reads a big-endian 4-byte unsigned integer from an offset in the * given array. * @param b The array to read from. * @param offset The offset in the array to start reading from. * @return A positive integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static long getUnsignedInt(final byte[] b, final int offset) { return getInt(b, offset) & 0x00000000FFFFFFFFL; } /** * Writes a big-endian 4-byte int at the begining of the given array. * @param b The array to write to. * @param n An integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static void setInt(final byte[] b, final int n) { setInt(b, n, 0); } /** * Writes a big-endian 4-byte int at an offset in the given array. * @param b The array to write to. * @param offset The offset in the array to start writing at. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static void setInt(final byte[] b, final int n, final int offset) { b[offset + 0] = (byte) (n >>> 24); b[offset + 1] = (byte) (n >>> 16); b[offset + 2] = (byte) (n >>> 8); b[offset + 3] = (byte) (n >>> 0); } /** * Creates a new byte array containing a big-endian 4-byte integer. * @param n An integer. * @return A new byte array containing the given value. */ public static byte[] fromInt(final int n) { final byte[] b = new byte[4]; setInt(b, n); return b; } /** * Reads a big-endian 8-byte long from the begining of the given array. * @param b The array to read from. * @return A long integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static long getLong(final byte[] b) { return getLong(b, 0); } /** * Reads a big-endian 8-byte long from an offset in the given array. * @param b The array to read from. * @param offset The offset in the array to start reading from. * @return A long integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static long getLong(final byte[] b, final int offset) { return (b[offset + 0] & 0xFFL) << 56 | (b[offset + 1] & 0xFFL) << 48 | (b[offset + 2] & 0xFFL) << 40 | (b[offset + 3] & 0xFFL) << 32 | (b[offset + 4] & 0xFFL) << 24 | (b[offset + 5] & 0xFFL) << 16 | (b[offset + 6] & 0xFFL) << 8 | (b[offset + 7] & 0xFFL) << 0; } /** * Writes a big-endian 8-byte long at the begining of the given array. * @param b The array to write to. * @param n A long integer. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static void setLong(final byte[] b, final long n) { setLong(b, n, 0); } /** * Writes a big-endian 8-byte long at an offset in the given array. * @param b The array to write to. * @param offset The offset in the array to start writing at. * @throws IndexOutOfBoundsException if the byte array is too small. */ public static void setLong(final byte[] b, final long n, final int offset) { b[offset + 0] = (byte) (n >>> 56); b[offset + 1] = (byte) (n >>> 48); b[offset + 2] = (byte) (n >>> 40); b[offset + 3] = (byte) (n >>> 32); b[offset + 4] = (byte) (n >>> 24); b[offset + 5] = (byte) (n >>> 16); b[offset + 6] = (byte) (n >>> 8); b[offset + 7] = (byte) (n >>> 0); } /** * Creates a new byte array containing a big-endian 8-byte long integer. * @param n A long integer. * @return A new byte array containing the given value. */ public static byte[] fromLong(final long n) { final byte[] b = new byte[8]; setLong(b, n); return b; } // ---------------------------- // // Pretty-printing byte arrays. // // ---------------------------- // private static final byte[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; // This doesn't really belong here but it doesn't belong anywhere else // either, so let's put it close to the other pretty-printing functions. /** * Pretty-prints a {@code long} into a fixed-width hexadecimal number. * @return A string of the form {@code 0x0123456789ABCDEF}. */ public static String hex(long v) { final byte[] buf = new byte[2 + 16]; buf[0] = '0'; buf[1] = 'x'; int i = 2 + 16; do { buf[--i] = HEX[(int) v & 0x0F]; v >>>= 4; } while (v != 0); for (/**/; i > 1; i--) { buf[i] = '0'; } return new String(buf); } /** * {@code memcmp} in Java, hooray. * @param a First non-{@code null} byte array to compare. * @param b Second non-{@code null} byte array to compare. * @return 0 if the two arrays are identical, otherwise the difference * between the first two different bytes, otherwise the different between * their lengths. */ public static int memcmp(final byte[] a, final byte[] b) { final int length = Math.min(a.length, b.length); if (a == b) { // Do this after accessing a.length and b.length return 0; // in order to NPE if either a or b is null. } for (int i = 0; i < length; i++) { if (a[i] != b[i]) { return (a[i] & 0xFF) - (b[i] & 0xFF); // "promote" to unsigned. } } return a.length - b.length; } /** * Tests whether two byte arrays have the same contents. * @param a First non-{@code null} byte array to compare. * @param b Second non-{@code null} byte array to compare. * @return {@code true} if the two arrays are identical, * {@code false} otherwise. */ public static boolean equals(final byte[] a, final byte[] b) { return memcmp(a, b) == 0; } }