/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.io; import java.util.Arrays; /** * Utility for hexidecimal encoding and decoding. * * @author Middleware Services */ public final class Hex { /** Hexidecimal characters. */ private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', }; /** * Decode table which stores characters from 0 to f. Anything higher than 'f' is invalid so that is the max size of * the array. */ private static final byte[] DECODE = new byte['f' + 1]; /** * Initialize the DECODE table. */ // CheckStyle:MagicNumber OFF static { // set all values to -1 to indicate error Arrays.fill(DECODE, (byte) -1); // set values for hex 0-9 for (int i = '0'; i <= '9'; i++) { DECODE[i] = (byte) (i - '0'); } // set values for hex A-F for (int i = 'A'; i <= 'F'; i++) { DECODE[i] = (byte) (i - 'A' + 10); } // set values for hex a-f for (int i = 'a'; i <= 'f'; i++) { DECODE[i] = (byte) (i - 'a' + 10); } } // CheckStyle:MagicNumber ON /** Default constructor. */ private Hex() {} /** * This will convert the supplied value to a hex encoded string. Returns null if the supplied value is null. * * @param value to hex encode * * @return hex encoded value */ public static char[] encode(final byte[] value) { if (value == null) { return null; } final int l = value.length; final char[] encoded = new char[l << 1]; // CheckStyle:MagicNumber OFF for (int i = 0, j = 0; i < l; i++) { encoded[j++] = HEX_CHARS[(0xF0 & value[i]) >>> 4]; encoded[j++] = HEX_CHARS[0x0F & value[i]]; } // CheckStyle:MagicNumber ON return encoded; } /** * This will convert the supplied value from a hex encoded string. Returns null if the supplied value is null. * * @param value to hex decode * * @return hex decoded value * * @throws IllegalArgumentException if value is not valid hexidecimal */ public static byte[] decode(final char[] value) { if (value == null) { return null; } final int l = value.length; // CheckStyle:MagicNumber OFF if ((l & 0x01) != 0) { throw new IllegalArgumentException( String.format("Cannot decode odd number of characters for %s", String.valueOf(value))); } // CheckStyle:MagicNumber ON final byte[] decoded = new byte[l >> 1]; // CheckStyle:MagicNumber OFF for (int i = 0, j = 0; j < l; i++, j += 2) { final int high = decode(value, j) << 4; final int low = decode(value, j + 1); decoded[i] = (byte) ((high | low) & 0xFF); } // CheckStyle:MagicNumber ON return decoded; } /** * Decodes the supplied character to it's corresponding nibble. * * @param hex to read character from * @param i index of hex to read * * @return 0-15 integer * * @throws IllegalArgumentException if the character is not valid hex */ protected static int decode(final char[] hex, final int i) { final char c = hex[i]; if (c > 'f') { throw new IllegalArgumentException( String.format("Invalid hex character '%s' at position %s in %s", c, i, Arrays.toString(hex))); } final byte b = DECODE[c]; if (b < 0) { throw new IllegalArgumentException( String.format("Invalid hex character '%s' at position %s in %s", c, i, Arrays.toString(hex))); } return b; } }