1 /*
2  * Copyright (C) 2009 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 package com.android.providers.contacts.util;
17 
18 /**
19  * Basic hex operations: from byte array to string and vice versa.
20  *
21  * TODO: move to the framework and consider implementing as native code.
22  */
23 public class Hex {
24 
25     private static final char[] HEX_DIGITS = new char[]{
26             '0', '1', '2', '3', '4', '5', '6', '7',
27             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
28     };
29 
30     private static final char[] FIRST_CHAR = new char[256];
31     private static final char[] SECOND_CHAR = new char[256];
32     static {
33         for (int i = 0; i < 256; i++) {
34             FIRST_CHAR[i] = HEX_DIGITS[(i >> 4) & 0xF];
35             SECOND_CHAR[i] = HEX_DIGITS[i & 0xF];
36         }
37     }
38 
39     private static final byte[] DIGITS = new byte['f'+1];
40     static {
41         for (int i = 0; i <= 'F'; i++) {
42             DIGITS[i] = -1;
43         }
44         for (byte i = 0; i < 10; i++) {
45             DIGITS['0' + i] = i;
46         }
47         for (byte i = 0; i < 6; i++) {
48             DIGITS['A' + i] = (byte)(10 + i);
49             DIGITS['a' + i] = (byte)(10 + i);
50         }
51     }
52 
53     /**
54      * Quickly converts a byte array to a hexadecimal string representation.
55      *
56      * @param array byte array, possibly zero-terminated.
57      */
encodeHex(byte[] array, boolean zeroTerminated)58     public static String encodeHex(byte[] array, boolean zeroTerminated) {
59         char[] cArray = new char[array.length * 2];
60 
61         int j = 0;
62         for (int i = 0; i < array.length; i++) {
63             int index = array[i] & 0xFF;
64             if (zeroTerminated && index == 0 && i == array.length-1) {
65                 break;
66             }
67 
68             cArray[j++] = FIRST_CHAR[index];
69             cArray[j++] = SECOND_CHAR[index];
70         }
71 
72         return new String(cArray, 0, j);
73     }
74 
75     /**
76      * Quickly converts a hexadecimal string to a byte array.
77      *
78      * TODO Use checked exceptions instead of RuntimeException.  Apparently normalized names *may*
79      * contain non-hex strings and we want to make sure the provider won't crash even with such
80      * input.
81      */
decodeHex(String hexString)82     public static byte[] decodeHex(String hexString) {
83         int length = hexString.length();
84 
85         if ((length & 0x01) != 0) {
86             throw new IllegalArgumentException("Odd number of characters: " + hexString);
87         }
88 
89         boolean badHex = false;
90         byte[] out = new byte[length >> 1];
91         for (int i = 0, j = 0; j < length; i++) {
92             int c1 = hexString.charAt(j++);
93             if (c1 > 'f') {
94                 badHex = true;
95                 break;
96             }
97 
98             final byte d1 = DIGITS[c1];
99             if (d1 == -1) {
100                 badHex = true;
101                 break;
102             }
103 
104             int c2 = hexString.charAt(j++);
105             if (c2 > 'f') {
106                 badHex = true;
107                 break;
108             }
109 
110             final byte d2 = DIGITS[c2];
111             if (d2 == -1) {
112                 badHex = true;
113                 break;
114             }
115 
116             out[i] = (byte) (d1 << 4 | d2);
117         }
118 
119         if (badHex) {
120             throw new IllegalArgumentException("Invalid hexadecimal digit: " + hexString);
121         }
122 
123         return out;
124     }
125 }
126