001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.codec.binary; 019 020import java.nio.ByteBuffer; 021import java.nio.charset.Charset; 022 023import org.apache.commons.codec.BinaryDecoder; 024import org.apache.commons.codec.BinaryEncoder; 025import org.apache.commons.codec.CharEncoding; 026import org.apache.commons.codec.Charsets; 027import org.apache.commons.codec.DecoderException; 028import org.apache.commons.codec.EncoderException; 029 030/** 031 * Converts hexadecimal Strings. The charset used for certain operation can be set, the default is set in 032 * {@link #DEFAULT_CHARSET_NAME} 033 * 034 * This class is thread-safe. 035 * 036 * @since 1.1 037 */ 038public class Hex implements BinaryEncoder, BinaryDecoder { 039 040 /** 041 * Default charset is {@link Charsets#UTF_8} 042 * 043 * @since 1.7 044 */ 045 public static final Charset DEFAULT_CHARSET = Charsets.UTF_8; 046 047 /** 048 * Default charset name is {@link CharEncoding#UTF_8} 049 * 050 * @since 1.4 051 */ 052 public static final String DEFAULT_CHARSET_NAME = CharEncoding.UTF_8; 053 054 /** 055 * Used to build output as Hex 056 */ 057 private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 058 'e', 'f' }; 059 060 /** 061 * Used to build output as Hex 062 */ 063 private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 064 'E', 'F' }; 065 066 /** 067 * Converts a String representing hexadecimal values into an array of bytes of those same values. The returned array 068 * will be half the length of the passed String, as it takes two characters to represent any given byte. An 069 * exception is thrown if the passed String has an odd number of elements. 070 * 071 * @param data A String containing hexadecimal digits 072 * @return A byte array containing binary data decoded from the supplied char array. 073 * @throws DecoderException Thrown if an odd number or illegal of characters is supplied 074 * @since 1.11 075 */ 076 public static byte[] decodeHex(final String data) throws DecoderException { 077 return decodeHex(data.toCharArray()); 078 } 079 080 /** 081 * Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The 082 * returned array will be half the length of the passed array, as it takes two characters to represent any given 083 * byte. An exception is thrown if the passed char array has an odd number of elements. 084 * 085 * @param data An array of characters containing hexadecimal digits 086 * @return A byte array containing binary data decoded from the supplied char array. 087 * @throws DecoderException Thrown if an odd number or illegal of characters is supplied 088 */ 089 public static byte[] decodeHex(final char[] data) throws DecoderException { 090 091 final int len = data.length; 092 093 if ((len & 0x01) != 0) { 094 throw new DecoderException("Odd number of characters."); 095 } 096 097 final byte[] out = new byte[len >> 1]; 098 099 // two characters form the hex value. 100 for (int i = 0, j = 0; j < len; i++) { 101 int f = toDigit(data[j], j) << 4; 102 j++; 103 f = f | toDigit(data[j], j); 104 j++; 105 out[i] = (byte) (f & 0xFF); 106 } 107 108 return out; 109 } 110 111 /** 112 * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order. 113 * The returned array will be double the length of the passed array, as it takes two characters to represent any 114 * given byte. 115 * 116 * @param data a byte[] to convert to Hex characters 117 * @return A char[] containing lower-case hexadecimal characters 118 */ 119 public static char[] encodeHex(final byte[] data) { 120 return encodeHex(data, true); 121 } 122 123 /** 124 * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The 125 * returned array will be double the length of the passed array, as it takes two characters to represent any given 126 * byte. 127 * 128 * @param data a byte buffer to convert to Hex characters 129 * @return A char[] containing lower-case hexadecimal characters 130 * @since 1.11 131 */ 132 public static char[] encodeHex(final ByteBuffer data) { 133 return encodeHex(data, true); 134 } 135 136 /** 137 * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order. 138 * The returned array will be double the length of the passed array, as it takes two characters to represent any 139 * given byte. 140 * 141 * @param data a byte[] to convert to Hex characters 142 * @param toLowerCase <code>true</code> converts to lowercase, <code>false</code> to uppercase 143 * @return A char[] containing hexadecimal characters in the selected case 144 * @since 1.4 145 */ 146 public static char[] encodeHex(final byte[] data, final boolean toLowerCase) { 147 return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 148 } 149 150 /** 151 * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The 152 * returned array will be double the length of the passed array, as it takes two characters to represent any given 153 * byte. 154 * 155 * @param data a byte buffer to convert to Hex characters 156 * @param toLowerCase <code>true</code> converts to lowercase, <code>false</code> to uppercase 157 * @return A char[] containing hexadecimal characters in the selected case 158 * @since 1.11 159 */ 160 public static char[] encodeHex(final ByteBuffer data, final boolean toLowerCase) { 161 return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 162 } 163 164 /** 165 * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order. 166 * The returned array will be double the length of the passed array, as it takes two characters to represent any 167 * given byte. 168 * 169 * @param data a byte[] to convert to Hex characters 170 * @param toDigits the output alphabet (must contain at least 16 chars) 171 * @return A char[] containing the appropriate characters from the alphabet For best results, this should be either 172 * upper- or lower-case hex. 173 * @since 1.4 174 */ 175 protected static char[] encodeHex(final byte[] data, final char[] toDigits) { 176 final int l = data.length; 177 final char[] out = new char[l << 1]; 178 // two characters form the hex value. 179 for (int i = 0, j = 0; i < l; i++) { 180 out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; 181 out[j++] = toDigits[0x0F & data[i]]; 182 } 183 return out; 184 } 185 186 /** 187 * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The 188 * returned array will be double the length of the passed array, as it takes two characters to represent any given 189 * byte. 190 * 191 * @param byteBuffer a byte buffer to convert to Hex characters 192 * @param toDigits the output alphabet (must be at least 16 characters) 193 * @return A char[] containing the appropriate characters from the alphabet For best results, this should be either 194 * upper- or lower-case hex. 195 * @since 1.11 196 */ 197 protected static char[] encodeHex(final ByteBuffer byteBuffer, final char[] toDigits) { 198 return encodeHex(toByteArray(byteBuffer), toDigits); 199 } 200 201 /** 202 * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned 203 * String will be double the length of the passed array, as it takes two characters to represent any given byte. 204 * 205 * @param data a byte[] to convert to Hex characters 206 * @return A String containing lower-case hexadecimal characters 207 * @since 1.4 208 */ 209 public static String encodeHexString(final byte[] data) { 210 return new String(encodeHex(data)); 211 } 212 213 /** 214 * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned 215 * String will be double the length of the passed array, as it takes two characters to represent any given byte. 216 * 217 * @param data a byte[] to convert to Hex characters 218 * @param toLowerCase <code>true</code> converts to lowercase, <code>false</code> to uppercase 219 * @return A String containing lower-case hexadecimal characters 220 * @since 1.11 221 */ 222 public static String encodeHexString(final byte[] data, final boolean toLowerCase) { 223 return new String(encodeHex(data, toLowerCase)); 224 } 225 226 /** 227 * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned 228 * String will be double the length of the passed array, as it takes two characters to represent any given byte. 229 * 230 * @param data a byte buffer to convert to Hex characters 231 * @return A String containing lower-case hexadecimal characters 232 * @since 1.11 233 */ 234 public static String encodeHexString(final ByteBuffer data) { 235 return new String(encodeHex(data)); 236 } 237 238 /** 239 * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned 240 * String will be double the length of the passed array, as it takes two characters to represent any given byte. 241 * 242 * @param data a byte buffer to convert to Hex characters 243 * @param toLowerCase <code>true</code> converts to lowercase, <code>false</code> to uppercase 244 * @return A String containing lower-case hexadecimal characters 245 * @since 1.11 246 */ 247 public static String encodeHexString(final ByteBuffer data, final boolean toLowerCase) { 248 return new String(encodeHex(data, toLowerCase)); 249 } 250 251 private static byte[] toByteArray(final ByteBuffer byteBuffer) { 252 if (byteBuffer.hasArray()) { 253 return byteBuffer.array(); 254 } 255 final byte[] byteArray = new byte[byteBuffer.remaining()]; 256 byteBuffer.get(byteArray); 257 return byteArray; 258 } 259 260 /** 261 * Converts a hexadecimal character to an integer. 262 * 263 * @param ch A character to convert to an integer digit 264 * @param index The index of the character in the source 265 * @return An integer 266 * @throws DecoderException Thrown if ch is an illegal hex character 267 */ 268 protected static int toDigit(final char ch, final int index) throws DecoderException { 269 final int digit = Character.digit(ch, 16); 270 if (digit == -1) { 271 throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index); 272 } 273 return digit; 274 } 275 276 private final Charset charset; 277 278 /** 279 * Creates a new codec with the default charset name {@link #DEFAULT_CHARSET} 280 */ 281 public Hex() { 282 // use default encoding 283 this.charset = DEFAULT_CHARSET; 284 } 285 286 /** 287 * Creates a new codec with the given Charset. 288 * 289 * @param charset the charset. 290 * @since 1.7 291 */ 292 public Hex(final Charset charset) { 293 this.charset = charset; 294 } 295 296 /** 297 * Creates a new codec with the given charset name. 298 * 299 * @param charsetName the charset name. 300 * @throws java.nio.charset.UnsupportedCharsetException If the named charset is unavailable 301 * @since 1.4 302 * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable 303 */ 304 public Hex(final String charsetName) { 305 this(Charset.forName(charsetName)); 306 } 307 308 /** 309 * Converts an array of character bytes representing hexadecimal values into an array of bytes of those same values. 310 * The returned array will be half the length of the passed array, as it takes two characters to represent any given 311 * byte. An exception is thrown if the passed char array has an odd number of elements. 312 * 313 * @param array An array of character bytes containing hexadecimal digits 314 * @return A byte array containing binary data decoded from the supplied byte array (representing characters). 315 * @throws DecoderException Thrown if an odd number of characters is supplied to this function 316 * @see #decodeHex(char[]) 317 */ 318 @Override 319 public byte[] decode(final byte[] array) throws DecoderException { 320 return decodeHex(new String(array, getCharset()).toCharArray()); 321 } 322 323 /** 324 * Converts a buffer of character bytes representing hexadecimal values into an array of bytes of those same values. 325 * The returned array will be half the length of the passed array, as it takes two characters to represent any given 326 * byte. An exception is thrown if the passed char array has an odd number of elements. 327 * 328 * @param buffer An array of character bytes containing hexadecimal digits 329 * @return A byte array containing binary data decoded from the supplied byte array (representing characters). 330 * @throws DecoderException Thrown if an odd number of characters is supplied to this function 331 * @see #decodeHex(char[]) 332 * @since 1.11 333 */ 334 public byte[] decode(final ByteBuffer buffer) throws DecoderException { 335 return decodeHex(new String(toByteArray(buffer), getCharset()).toCharArray()); 336 } 337 338 /** 339 * Converts a String or an array of character bytes representing hexadecimal values into an array of bytes of those 340 * same values. The returned array will be half the length of the passed String or array, as it takes two characters 341 * to represent any given byte. An exception is thrown if the passed char array has an odd number of elements. 342 * 343 * @param object A String, ByteBuffer, byte[], or an array of character bytes containing hexadecimal digits 344 * @return A byte array containing binary data decoded from the supplied byte array (representing characters). 345 * @throws DecoderException Thrown if an odd number of characters is supplied to this function or the object is not 346 * a String or char[] 347 * @see #decodeHex(char[]) 348 */ 349 @Override 350 public Object decode(final Object object) throws DecoderException { 351 if (object instanceof String) { 352 return decode(((String) object).toCharArray()); 353 } else if (object instanceof byte[]) { 354 return decode((byte[]) object); 355 } else if (object instanceof ByteBuffer) { 356 return decode((ByteBuffer) object); 357 } else { 358 try { 359 return decodeHex((char[]) object); 360 } catch (final ClassCastException e) { 361 throw new DecoderException(e.getMessage(), e); 362 } 363 } 364 } 365 366 /** 367 * Converts an array of bytes into an array of bytes for the characters representing the hexadecimal values of each 368 * byte in order. The returned array will be double the length of the passed array, as it takes two characters to 369 * represent any given byte. 370 * <p> 371 * The conversion from hexadecimal characters to the returned bytes is performed with the charset named by 372 * {@link #getCharset()}. 373 * </p> 374 * 375 * @param array a byte[] to convert to Hex characters 376 * @return A byte[] containing the bytes of the lower-case hexadecimal characters 377 * @since 1.7 No longer throws IllegalStateException if the charsetName is invalid. 378 * @see #encodeHex(byte[]) 379 */ 380 @Override 381 public byte[] encode(final byte[] array) { 382 return encodeHexString(array).getBytes(this.getCharset()); 383 } 384 385 /** 386 * Converts byte buffer into an array of bytes for the characters representing the hexadecimal values of each byte 387 * in order. The returned array will be double the length of the passed array, as it takes two characters to 388 * represent any given byte. 389 * <p> 390 * The conversion from hexadecimal characters to the returned bytes is performed with the charset named by 391 * {@link #getCharset()}. 392 * </p> 393 * 394 * @param array a byte buffer to convert to Hex characters 395 * @return A byte[] containing the bytes of the lower-case hexadecimal characters 396 * @see #encodeHex(byte[]) 397 * @since 1.11 398 */ 399 public byte[] encode(final ByteBuffer array) { 400 return encodeHexString(array).getBytes(this.getCharset()); 401 } 402 403 /** 404 * Converts a String or an array of bytes into an array of characters representing the hexadecimal values of each 405 * byte in order. The returned array will be double the length of the passed String or array, as it takes two 406 * characters to represent any given byte. 407 * <p> 408 * The conversion from hexadecimal characters to bytes to be encoded to performed with the charset named by 409 * {@link #getCharset()}. 410 * </p> 411 * 412 * @param object a String, ByteBuffer, or byte[] to convert to Hex characters 413 * @return A char[] containing lower-case hexadecimal characters 414 * @throws EncoderException Thrown if the given object is not a String or byte[] 415 * @see #encodeHex(byte[]) 416 */ 417 @Override 418 public Object encode(final Object object) throws EncoderException { 419 byte[] byteArray; 420 if (object instanceof String) { 421 byteArray = ((String) object).getBytes(this.getCharset()); 422 } else if (object instanceof ByteBuffer) { 423 byteArray = toByteArray((ByteBuffer) object); 424 } else { 425 try { 426 byteArray = (byte[]) object; 427 } catch (final ClassCastException e) { 428 throw new EncoderException(e.getMessage(), e); 429 } 430 } 431 return encodeHex(byteArray); 432 } 433 434 /** 435 * Gets the charset. 436 * 437 * @return the charset. 438 * @since 1.7 439 */ 440 public Charset getCharset() { 441 return this.charset; 442 } 443 444 /** 445 * Gets the charset name. 446 * 447 * @return the charset name. 448 * @since 1.4 449 */ 450 public String getCharsetName() { 451 return this.charset.name(); 452 } 453 454 /** 455 * Returns a string representation of the object, which includes the charset name. 456 * 457 * @return a string representation of the object. 458 */ 459 @Override 460 public String toString() { 461 return super.toString() + "[charsetName=" + this.charset + "]"; 462 } 463}