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