package com.cloudhopper.commons.util; /* * #%L * ch-commons-util * %% * Copyright (C) 2012 Cloudhopper by Twitter * %% * 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. * #L% */ import static com.cloudhopper.commons.util.HexUtil.toByteArray; import static com.cloudhopper.commons.util.HexUtil.toHexString; import java.util.Arrays; /** * Utility class for representing hex strings. Instances are immutable. Hex digits are always in caps. * * Primarily used to aid testing, the implementation is naive and not performant. * <b>NOT RECOMMENDED FOR USE IN PRODUCTION</b>. * * @author John Woolf (twitter: @jwoolf330 or <a href="http://twitter.com/jwoolf330" target=window>http://twitter.com/jwoolf330</a>) * */ public final class HexString { public static final HexString NULL = new HexString(new byte[0], ""); /** * Create a new <code>HexString</code> instance from the given hexadecimal string. * If <code>null</code> or an empty string is passed, will return a <code>HexString</code> instance * with empty hex value and zero-length byte array. * * @param hex The hexadecimal string * @return Immutable <code>HexString</code> instance encapsulating the hexadecimal string * @throws IllegalArgumentException if malformed hex string (invalid or odd number of characters) is passed */ public static HexString valueOf(String hex) { return (hex == null || hex.equals("")) ? NULL : createHexString(hex); } /** * Create a new <code>HexString</code> instance from the given byte array. * If <code>null</code> or zero-length byte array is passed, will return a <code>HexString</code> instance * with empty hex value and zero-length byte array. * * @param bytes The byte array * @return Immutable <code>HexString</code> instance encapsulating the byte array */ public static HexString valueOf(byte[] bytes) { return (bytes == null || bytes.length == 0) ? NULL : createHexString(bytes); } private static HexString createHexString(String hex) { // though method is private, leaving checks in place to show intent if (hex == null) { throw new IllegalArgumentException("hex string argument cannot be null; use HexString.NULL instead"); } else if (hex.equals("")) { throw new IllegalArgumentException("hex string argument cannot be empty; use HexString.NULL instead"); } byte[] bytes = toByteArray(hex); return new HexString(bytes, hex.toUpperCase()); } private static HexString createHexString(byte[] bytes) { // though method is private, leaving checks in place to show intent if (bytes == null) { throw new IllegalArgumentException("bytes argument cannot be null; use HexString.NULL instead"); } else if (bytes.length == 0) { throw new IllegalArgumentException("bytes argument cannot be zero length; use HexString.NULL instead"); } byte[] copyOfbytes = copyByteArray(bytes); String hex = toHexString(copyOfbytes).toUpperCase(); return new HexString(copyOfbytes, hex); } private static byte[] copyByteArray(byte[] bytes) { return Arrays.copyOf(bytes, bytes.length); } private final String hex; private final byte[] bytes; private HexString(byte[] bytes, String hex) { this.bytes = bytes; this.hex = hex; } /** * @return The instance as an unformatted hex string - i.e. \"AB45C03F\" */ public String asString() { return hex; } /** * N.B. <code>asBytes()</code> returns a copy of the underlying byte array * * @return The instance as its underlying byte array */ public byte[] asBytes() { return copyByteArray(bytes); } @Override public String toString() { return "0x" + hex; } @Override public boolean equals(Object other) { if (other != null && other instanceof HexString) { HexString hexString = (HexString) other; return this.hex.equals(hexString.hex); } else { return false; } } @Override public int hashCode() { return this.hex.hashCode(); } }