Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.util;
     18 
     19 /**
     20  * Hexadecimal encoding where each byte is represented by two hexadecimal digits.
     21  */
     22 public class HexEncoding {
     23 
     24     /** Hidden constructor to prevent instantiation. */
     25     private HexEncoding() {}
     26 
     27     private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
     28 
     29     /**
     30      * Encodes the provided data as a sequence of hexadecimal characters.
     31      */
     32     public static char[] encode(byte[] data) {
     33         return encode(data, 0, data.length);
     34     }
     35 
     36     /**
     37      * Encodes the provided data as a sequence of hexadecimal characters.
     38      */
     39     public static char[] encode(byte[] data, int offset, int len) {
     40         char[] result = new char[len * 2];
     41         for (int i = 0; i < len; i++) {
     42             byte b = data[offset + i];
     43             int resultIndex = 2 * i;
     44             result[resultIndex] = (HEX_DIGITS[(b >>> 4) & 0x0f]);
     45             result[resultIndex + 1] = (HEX_DIGITS[b & 0x0f]);
     46         }
     47 
     48         return result;
     49     }
     50 
     51     /**
     52      * Encodes the provided data as a sequence of hexadecimal characters.
     53      */
     54     public static String encodeToString(byte[] data) {
     55         return new String(encode(data));
     56     }
     57 
     58     /**
     59      * Decodes the provided hexadecimal string into a byte array.  Odd-length inputs
     60      * are not allowed.
     61      *
     62      * Throws an {@code IllegalArgumentException} if the input is malformed.
     63      */
     64     public static byte[] decode(String encoded) throws IllegalArgumentException {
     65         return decode(encoded.toCharArray());
     66     }
     67 
     68     /**
     69      * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
     70      * is {@code true} odd-length inputs are allowed and the first character is interpreted
     71      * as the lower bits of the first result byte.
     72      *
     73      * Throws an {@code IllegalArgumentException} if the input is malformed.
     74      */
     75     public static byte[] decode(String encoded, boolean allowSingleChar) throws IllegalArgumentException {
     76         return decode(encoded.toCharArray(), allowSingleChar);
     77     }
     78 
     79     /**
     80      * Decodes the provided hexadecimal string into a byte array.  Odd-length inputs
     81      * are not allowed.
     82      *
     83      * Throws an {@code IllegalArgumentException} if the input is malformed.
     84      */
     85     public static byte[] decode(char[] encoded) throws IllegalArgumentException {
     86         return decode(encoded, false);
     87     }
     88 
     89     /**
     90      * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
     91      * is {@code true} odd-length inputs are allowed and the first character is interpreted
     92      * as the lower bits of the first result byte.
     93      *
     94      * Throws an {@code IllegalArgumentException} if the input is malformed.
     95      */
     96     public static byte[] decode(char[] encoded, boolean allowSingleChar) throws IllegalArgumentException {
     97         int resultLengthBytes = (encoded.length + 1) / 2;
     98         byte[] result = new byte[resultLengthBytes];
     99 
    100         int resultOffset = 0;
    101         int i = 0;
    102         if (allowSingleChar) {
    103             if ((encoded.length % 2) != 0) {
    104                 // Odd number of digits -- the first digit is the lower 4 bits of the first result byte.
    105                 result[resultOffset++] = (byte) toDigit(encoded, i);
    106                 i++;
    107             }
    108         } else {
    109             if ((encoded.length % 2) != 0) {
    110                 throw new IllegalArgumentException("Invalid input length: " + encoded.length);
    111             }
    112         }
    113 
    114         for (int len = encoded.length; i < len; i += 2) {
    115             result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
    116         }
    117 
    118         return result;
    119     }
    120 
    121     private static int toDigit(char[] str, int offset) throws IllegalArgumentException {
    122         // NOTE: that this isn't really a code point in the traditional sense, since we're
    123         // just rejecting surrogate pairs outright.
    124         int pseudoCodePoint = str[offset];
    125 
    126         if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {
    127             return pseudoCodePoint - '0';
    128         } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {
    129             return 10 + (pseudoCodePoint - 'a');
    130         } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {
    131             return 10 + (pseudoCodePoint - 'A');
    132         }
    133 
    134         throw new IllegalArgumentException("Illegal char: " + str[offset] +
    135                 " at offset " + offset);
    136     }
    137 }
    138