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 */
16package 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 */
23public 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     */
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     */
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