Hex.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.codec.binary;

  18. import java.nio.ByteBuffer;
  19. import java.nio.charset.Charset;

  20. import org.apache.commons.codec.BinaryDecoder;
  21. import org.apache.commons.codec.BinaryEncoder;
  22. import org.apache.commons.codec.CharEncoding;
  23. import org.apache.commons.codec.Charsets;
  24. import org.apache.commons.codec.DecoderException;
  25. import org.apache.commons.codec.EncoderException;

  26. /**
  27.  * Converts hexadecimal Strings. The charset used for certain operation can be set, the default is set in
  28.  * {@link #DEFAULT_CHARSET_NAME}
  29.  *
  30.  * This class is thread-safe.
  31.  *
  32.  * @since 1.1
  33.  * @version $Id: Hex.java 1811344 2017-10-06 15:19:57Z ggregory $
  34.  */
  35. public class Hex implements BinaryEncoder, BinaryDecoder {

  36.     /**
  37.      * Default charset is {@link Charsets#UTF_8}
  38.      *
  39.      * @since 1.7
  40.      */
  41.     public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;

  42.     /**
  43.      * Default charset name is {@link CharEncoding#UTF_8}
  44.      *
  45.      * @since 1.4
  46.      */
  47.     public static final String DEFAULT_CHARSET_NAME = CharEncoding.UTF_8;

  48.     /**
  49.      * Used to build output as Hex
  50.      */
  51.     private static final char[] DIGITS_LOWER =
  52.         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

  53.     /**
  54.      * Used to build output as Hex
  55.      */
  56.     private static final char[] DIGITS_UPPER =
  57.         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

  58.     /**
  59.      * Converts a String representing hexadecimal values into an array of bytes of those same values. The
  60.      * returned array will be half the length of the passed String, as it takes two characters to represent any given
  61.      * byte. An exception is thrown if the passed String has an odd number of elements.
  62.      *
  63.      * @param data
  64.      *            A String containing hexadecimal digits
  65.      * @return A byte array containing binary data decoded from the supplied char array.
  66.      * @throws DecoderException
  67.      *             Thrown if an odd number or illegal of characters is supplied
  68.      * @since 1.11
  69.      */
  70.     public static byte[] decodeHex(final String data) throws DecoderException {
  71.         return decodeHex(data.toCharArray());
  72.     }

  73.     /**
  74.      * Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
  75.      * returned array will be half the length of the passed array, as it takes two characters to represent any given
  76.      * byte. An exception is thrown if the passed char array has an odd number of elements.
  77.      *
  78.      * @param data
  79.      *            An array of characters containing hexadecimal digits
  80.      * @return A byte array containing binary data decoded from the supplied char array.
  81.      * @throws DecoderException
  82.      *             Thrown if an odd number or illegal of characters is supplied
  83.      */
  84.     public static byte[] decodeHex(final char[] data) throws DecoderException {

  85.         final int len = data.length;

  86.         if ((len & 0x01) != 0) {
  87.             throw new DecoderException("Odd number of characters.");
  88.         }

  89.         final byte[] out = new byte[len >> 1];

  90.         // two characters form the hex value.
  91.         for (int i = 0, j = 0; j < len; i++) {
  92.             int f = toDigit(data[j], j) << 4;
  93.             j++;
  94.             f = f | toDigit(data[j], j);
  95.             j++;
  96.             out[i] = (byte) (f & 0xFF);
  97.         }

  98.         return out;
  99.     }

  100.     /**
  101.      * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
  102.      * The returned array will be double the length of the passed array, as it takes two characters to represent any
  103.      * given byte.
  104.      *
  105.      * @param data
  106.      *            a byte[] to convert to Hex characters
  107.      * @return A char[] containing lower-case hexadecimal characters
  108.      */
  109.     public static char[] encodeHex(final byte[] data) {
  110.         return encodeHex(data, true);
  111.     }

  112.     /**
  113.      * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order.
  114.      * The returned array will be double the length of the passed array, as it takes two characters to represent any
  115.      * given byte.
  116.      *
  117.      * @param data
  118.      *            a byte buffer to convert to Hex characters
  119.      * @return A char[] containing lower-case hexadecimal characters
  120.      * @since 1.11
  121.      */
  122.     public static char[] encodeHex(final ByteBuffer data) {
  123.         return encodeHex(data, true);
  124.     }

  125.     /**
  126.      * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
  127.      * The returned array will be double the length of the passed array, as it takes two characters to represent any
  128.      * given byte.
  129.      *
  130.      * @param data
  131.      *            a byte[] to convert to Hex characters
  132.      * @param toLowerCase
  133.      *            <code>true</code> converts to lowercase, <code>false</code> to uppercase
  134.      * @return A char[] containing hexadecimal characters in the selected case
  135.      * @since 1.4
  136.      */
  137.     public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
  138.         return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
  139.     }

  140.     /**
  141.      * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order.
  142.      * The returned array will be double the length of the passed array, as it takes two characters to represent any
  143.      * given byte.
  144.      *
  145.      * @param data
  146.      *            a byte buffer to convert to Hex characters
  147.      * @param toLowerCase
  148.      *            <code>true</code> converts to lowercase, <code>false</code> to uppercase
  149.      * @return A char[] containing hexadecimal characters in the selected case
  150.      * @since 1.11
  151.      */
  152.     public static char[] encodeHex(final ByteBuffer data, final boolean toLowerCase) {
  153.         return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
  154.     }

  155.     /**
  156.      * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
  157.      * The returned array will be double the length of the passed array, as it takes two characters to represent any
  158.      * given byte.
  159.      *
  160.      * @param data
  161.      *            a byte[] to convert to Hex characters
  162.      * @param toDigits
  163.      *            the output alphabet (must contain at least 16 chars)
  164.      * @return A char[] containing the appropriate characters from the alphabet
  165.      *         For best results, this should be either upper- or lower-case hex.
  166.      * @since 1.4
  167.      */
  168.     protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
  169.         final int l = data.length;
  170.         final char[] out = new char[l << 1];
  171.         // two characters form the hex value.
  172.         for (int i = 0, j = 0; i < l; i++) {
  173.             out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
  174.             out[j++] = toDigits[0x0F & data[i]];
  175.         }
  176.         return out;
  177.     }

  178.     /**
  179.      * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order.
  180.      * The returned array will be double the length of the passed array, as it takes two characters to represent any
  181.      * given byte.
  182.      *
  183.      * @param data
  184.      *            a byte buffer to convert to Hex characters
  185.      * @param toDigits
  186.      *            the output alphabet (must be at least 16 characters)
  187.      * @return A char[] containing the appropriate characters from the alphabet
  188.      *         For best results, this should be either upper- or lower-case hex.
  189.      * @since 1.11
  190.      */
  191.     protected static char[] encodeHex(final ByteBuffer data, final char[] toDigits) {
  192.         return encodeHex(data.array(), toDigits);
  193.     }

  194.     /**
  195.      * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
  196.      * String will be double the length of the passed array, as it takes two characters to represent any given byte.
  197.      *
  198.      * @param data
  199.      *            a byte[] to convert to Hex characters
  200.      * @return A String containing lower-case hexadecimal characters
  201.      * @since 1.4
  202.      */
  203.     public static String encodeHexString(final byte[] data) {
  204.         return new String(encodeHex(data));
  205.     }

  206.     /**
  207.      * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
  208.      * String will be double the length of the passed array, as it takes two characters to represent any given byte.
  209.      *
  210.      * @param data
  211.      *            a byte[] to convert to Hex characters
  212.      * @param toLowerCase
  213.      *            <code>true</code> converts to lowercase, <code>false</code> to uppercase
  214.      * @return A String containing lower-case hexadecimal characters
  215.      * @since 1.11
  216.      */
  217.     public static String encodeHexString(final byte[] data, final boolean toLowerCase) {
  218.         return new String(encodeHex(data, toLowerCase));
  219.     }

  220.     /**
  221.      * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
  222.      * String will be double the length of the passed array, as it takes two characters to represent any given byte.
  223.      *
  224.      * @param data
  225.      *            a byte buffer to convert to Hex characters
  226.      * @return A String containing lower-case hexadecimal characters
  227.      * @since 1.11
  228.      */
  229.     public static String encodeHexString(final ByteBuffer data) {
  230.         return new String(encodeHex(data));
  231.     }

  232.     /**
  233.      * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
  234.      * String will be double the length of the passed array, as it takes two characters to represent any given byte.
  235.      *
  236.      * @param data
  237.      *            a byte buffer to convert to Hex characters
  238.      * @param toLowerCase
  239.      *            <code>true</code> converts to lowercase, <code>false</code> to uppercase
  240.      * @return A String containing lower-case hexadecimal characters
  241.      * @since 1.11
  242.      */
  243.     public static String encodeHexString(final ByteBuffer data, final boolean toLowerCase) {
  244.         return new String(encodeHex(data, toLowerCase));
  245.     }

  246.     /**
  247.      * Converts a hexadecimal character to an integer.
  248.      *
  249.      * @param ch
  250.      *            A character to convert to an integer digit
  251.      * @param index
  252.      *            The index of the character in the source
  253.      * @return An integer
  254.      * @throws DecoderException
  255.      *             Thrown if ch is an illegal hex character
  256.      */
  257.     protected static int toDigit(final char ch, final int index) throws DecoderException {
  258.         final int digit = Character.digit(ch, 16);
  259.         if (digit == -1) {
  260.             throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index);
  261.         }
  262.         return digit;
  263.     }

  264.     private final Charset charset;

  265.     /**
  266.      * Creates a new codec with the default charset name {@link #DEFAULT_CHARSET}
  267.      */
  268.     public Hex() {
  269.         // use default encoding
  270.         this.charset = DEFAULT_CHARSET;
  271.     }

  272.     /**
  273.      * Creates a new codec with the given Charset.
  274.      *
  275.      * @param charset
  276.      *            the charset.
  277.      * @since 1.7
  278.      */
  279.     public Hex(final Charset charset) {
  280.         this.charset = charset;
  281.     }

  282.     /**
  283.      * Creates a new codec with the given charset name.
  284.      *
  285.      * @param charsetName
  286.      *            the charset name.
  287.      * @throws java.nio.charset.UnsupportedCharsetException
  288.      *             If the named charset is unavailable
  289.      * @since 1.4
  290.      * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
  291.      */
  292.     public Hex(final String charsetName) {
  293.         this(Charset.forName(charsetName));
  294.     }

  295.     /**
  296.      * Converts an array of character bytes representing hexadecimal values into an array of bytes of those same values.
  297.      * The returned array will be half the length of the passed array, as it takes two characters to represent any given
  298.      * byte. An exception is thrown if the passed char array has an odd number of elements.
  299.      *
  300.      * @param array
  301.      *            An array of character bytes containing hexadecimal digits
  302.      * @return A byte array containing binary data decoded from the supplied byte array (representing characters).
  303.      * @throws DecoderException
  304.      *             Thrown if an odd number of characters is supplied to this function
  305.      * @see #decodeHex(char[])
  306.      */
  307.     @Override
  308.     public byte[] decode(final byte[] array) throws DecoderException {
  309.         return decodeHex(new String(array, getCharset()).toCharArray());
  310.     }

  311.     /**
  312.      * Converts a buffer of character bytes representing hexadecimal values into an array of bytes of those same values.
  313.      * The returned array will be half the length of the passed array, as it takes two characters to represent any given
  314.      * byte. An exception is thrown if the passed char array has an odd number of elements.
  315.      *
  316.      * @param buffer
  317.      *            An array of character bytes containing hexadecimal digits
  318.      * @return A byte array containing binary data decoded from the supplied byte array (representing characters).
  319.      * @throws DecoderException
  320.      *             Thrown if an odd number of characters is supplied to this function
  321.      * @see #decodeHex(char[])
  322.      * @since 1.11
  323.      */
  324.     public byte[] decode(final ByteBuffer buffer) throws DecoderException {
  325.         return decodeHex(new String(buffer.array(), getCharset()).toCharArray());
  326.     }

  327.     /**
  328.      * Converts a String or an array of character bytes representing hexadecimal values into an array of bytes of those
  329.      * same values. The returned array will be half the length of the passed String or array, as it takes two characters
  330.      * to represent any given byte. An exception is thrown if the passed char array has an odd number of elements.
  331.      *
  332.      * @param object
  333.      *            A String, ByteBuffer, byte[], or an array of character bytes containing hexadecimal digits
  334.      * @return A byte array containing binary data decoded from the supplied byte array (representing characters).
  335.      * @throws DecoderException
  336.      *             Thrown if an odd number of characters is supplied to this function or the object is not a String or
  337.      *             char[]
  338.      * @see #decodeHex(char[])
  339.      */
  340.     @Override
  341.     public Object decode(final Object object) throws DecoderException {
  342.         if (object instanceof String) {
  343.             return decode(((String) object).toCharArray());
  344.         } else if (object instanceof byte[]) {
  345.             return decode((byte[]) object);
  346.         } else if (object instanceof ByteBuffer) {
  347.             return decode((ByteBuffer) object);
  348.         } else {
  349.             try {
  350.                 return decodeHex((char[]) object);
  351.             } catch (final ClassCastException e) {
  352.                 throw new DecoderException(e.getMessage(), e);
  353.             }
  354.         }
  355.     }

  356.     /**
  357.      * Converts an array of bytes into an array of bytes for the characters representing the hexadecimal values of each
  358.      * byte in order. The returned array will be double the length of the passed array, as it takes two characters to
  359.      * represent any given byte.
  360.      * <p>
  361.      * The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
  362.      * {@link #getCharset()}.
  363.      * </p>
  364.      *
  365.      * @param array
  366.      *            a byte[] to convert to Hex characters
  367.      * @return A byte[] containing the bytes of the lower-case hexadecimal characters
  368.      * @since 1.7 No longer throws IllegalStateException if the charsetName is invalid.
  369.      * @see #encodeHex(byte[])
  370.      */
  371.     @Override
  372.     public byte[] encode(final byte[] array) {
  373.         return encodeHexString(array).getBytes(this.getCharset());
  374.     }

  375.     /**
  376.      * Converts byte buffer into an array of bytes for the characters representing the hexadecimal values of each
  377.      * byte in order. The returned array will be double the length of the passed array, as it takes two characters to
  378.      * represent any given byte.
  379.      * <p>
  380.      * The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
  381.      * {@link #getCharset()}.
  382.      * </p>
  383.      *
  384.      * @param array
  385.      *            a byte buffer to convert to Hex characters
  386.      * @return A byte[] containing the bytes of the lower-case hexadecimal characters
  387.      * @see #encodeHex(byte[])
  388.      * @since 1.11
  389.      */
  390.     public byte[] encode(final ByteBuffer array) {
  391.         return encodeHexString(array).getBytes(this.getCharset());
  392.     }

  393.     /**
  394.      * Converts a String or an array of bytes into an array of characters representing the hexadecimal values of each
  395.      * byte in order. The returned array will be double the length of the passed String or array, as it takes two
  396.      * characters to represent any given byte.
  397.      * <p>
  398.      * The conversion from hexadecimal characters to bytes to be encoded to performed with the charset named by
  399.      * {@link #getCharset()}.
  400.      * </p>
  401.      *
  402.      * @param object
  403.      *            a String, ByteBuffer, or byte[] to convert to Hex characters
  404.      * @return A char[] containing lower-case hexadecimal characters
  405.      * @throws EncoderException
  406.      *             Thrown if the given object is not a String or byte[]
  407.      * @see #encodeHex(byte[])
  408.      */
  409.     @Override
  410.     public Object encode(final Object object) throws EncoderException {
  411.         byte[] byteArray;
  412.         if (object instanceof String) {
  413.             byteArray = ((String) object).getBytes(this.getCharset());
  414.         } else if (object instanceof ByteBuffer) {
  415.             byteArray = ((ByteBuffer) object).array();
  416.         } else {
  417.             try {
  418.                 byteArray = (byte[]) object;
  419.             } catch (final ClassCastException e) {
  420.                 throw new EncoderException(e.getMessage(), e);
  421.             }
  422.         }
  423.         return encodeHex(byteArray);
  424.     }

  425.     /**
  426.      * Gets the charset.
  427.      *
  428.      * @return the charset.
  429.      * @since 1.7
  430.      */
  431.     public Charset getCharset() {
  432.         return this.charset;
  433.     }

  434.     /**
  435.      * Gets the charset name.
  436.      *
  437.      * @return the charset name.
  438.      * @since 1.4
  439.      */
  440.     public String getCharsetName() {
  441.         return this.charset.name();
  442.     }

  443.     /**
  444.      * Returns a string representation of the object, which includes the charset name.
  445.      *
  446.      * @return a string representation of the object.
  447.      */
  448.     @Override
  449.     public String toString() {
  450.         return super.toString() + "[charsetName=" + this.charset + "]";
  451.     }
  452. }