Java tutorial
/** * Copyright 2011 LiveRamp * * 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 com.liveramp.commons.util; import java.io.UnsupportedEncodingException; import org.apache.commons.codec.binary.Hex; import java.nio.ByteBuffer; import java.util.Comparator; import com.google.common.primitives.UnsignedBytes; public class BytesUtils { private static final Comparator<byte[]> BYTES_COMPARATOR = UnsignedBytes.lexicographicalComparator(); private static final String CHARSET = "utf-8"; public static int compareBytesUnsigned(byte[] a, int aOff, byte[] b, int bOff, int len) { if (len > a.length - aOff || len > b.length - bOff) { throw new RuntimeException("Not enough bytes left to compare!"); } for (int i = 0; i < len; i++) { // we want our comparison to be unsigned. if we just compare the bytes, // it will be a signed comparison. to drop the sign, we convert the byte // to an int, then mask off all the upper bits. if we don't do the // masking, then the signed byte will just get sign-extended and remain // negative. final int ab = a[aOff + i] & 0xff; final int bb = b[bOff + i] & 0xff; if (ab > bb) { return 1; } else if (ab < bb) { return -1; } } return 0; } public static int compareBytesUnsigned(ByteBuffer a, ByteBuffer b) { if (a.remaining() != b.remaining()) { throw new RuntimeException( "Cannot compare ByteBuffers that have a different number of remaining elements."); } return compareBytesUnsigned(a.array(), a.arrayOffset() + a.position(), b.array(), b.arrayOffset() + b.position(), a.remaining()); } public static byte[] intToBytes(int value) { return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value }; } public static int bytesToInt(byte[] b) { return (b[0] << 24) + ((b[1] & 0xFF) << 16) + ((b[2] & 0xFF) << 8) + (b[3] & 0xFF); } public static String bytesToString(byte[] b) { try { return new String(b, CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } public static byte[] stringToBytes(String s) { try { return s.getBytes(CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } // Make a deep copy of the remaining bytes of the given ByteBuffer. // The new buffer's capacity is trimmed down to the required size (remaining bytes). public static ByteBuffer byteBufferDeepCopy(ByteBuffer src) { ByteBuffer copy = ByteBuffer.allocate(src.remaining()).put(src.slice()); copy.flip(); return copy; } // Does a deep copy of src into dst. Allocation is performed only if necessary. // Return of this function should be assigned to dst. public static ByteBuffer byteBufferDeepCopy(ByteBuffer src, ByteBuffer dst) { if (dst == null || dst.capacity() < src.remaining()) { dst = byteBufferDeepCopy(src); } else { dst.rewind(); dst.limit(src.remaining()); dst.put(src.slice()); dst.flip(); } return dst; } // Each byte is converted to its hexadecimal 2 character string // representation. Bytes are separated by spaces in the output. public static String bytesToHexString(ByteBuffer b) { StringBuilder result = new StringBuilder(); for (int i = 0; i < b.remaining(); ++i) { final int v = b.array()[b.arrayOffset() + b.position() + i] & 0xff; if (i > 0) { result.append(" "); } if (v < 16) { result.append("0"); } result.append(Integer.toString(v, 16)); } return result.toString(); } // Each sequence of 2 characters is considered to be the hexadecimal // representation of a byte. Blanks are ignored. public static ByteBuffer hexStringToBytes(String hexString) { hexString = hexString.replaceAll("\\W+", ""); if (hexString.length() % 2 != 0) { throw new RuntimeException("Input string's size must be even."); } byte[] result = new byte[hexString.length() / 2]; for (int i = 0; i < hexString.length(); i += 2) { result[i / 2] = (byte) Integer.valueOf(hexString.substring(i, i + 2), 16).intValue(); } return ByteBuffer.wrap(result); } /** * If the given ByteBuffer wraps completely its underlying byte array, return the underlying * byte array (no copy). Otherwise, return a deep copy of the range represented by the given * ByteBuffer. * * @param byteBuffer */ public static byte[] byteBufferToByteArray(ByteBuffer byteBuffer) { if (wrapsFullArray(byteBuffer)) { return byteBuffer.array(); } byte[] target = new byte[byteBuffer.remaining()]; byteBufferToByteArray(byteBuffer, target, 0); return target; } public static int byteBufferToByteArray(ByteBuffer byteBuffer, byte[] target, int offset) { int remaining = byteBuffer.remaining(); System.arraycopy(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), target, offset, remaining); return remaining; } public static byte[] deepCopyByteBufferToByteArray(ByteBuffer byteBuffer) { byte[] result = new byte[byteBuffer.remaining()]; System.arraycopy(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), result, 0, byteBuffer.remaining()); return result; } public static boolean wrapsFullArray(ByteBuffer byteBuffer) { return byteBuffer.hasArray() && byteBuffer.position() == 0 && byteBuffer.arrayOffset() == 0 && byteBuffer.remaining() == byteBuffer.capacity(); } public static int compareBytes(byte[] b1, byte[] b2) { return BYTES_COMPARATOR.compare(b1, b2); } public static String encodeHex(byte[] bytes) { return String.valueOf(Hex.encodeHex(bytes)); } }