1d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen/*
2d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * Copyright (C) 2017 The Android Open Source Project
3d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen *
4d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * Licensed under the Apache License, Version 2.0 (the "License");
5d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * you may not use this file except in compliance with the License.
6d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * You may obtain a copy of the License at
7d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen *
8d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen *      http://www.apache.org/licenses/LICENSE-2.0
9d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen *
10d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * Unless required by applicable law or agreed to in writing, software
11d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * distributed under the License is distributed on an "AS IS" BASIS,
12d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * See the License for the specific language governing permissions and
14d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * limitations under the License.
15d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen */
16d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
17d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjenpackage android.util;
18d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
19d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen/**
20d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * A utility class for common byte array to hex string operations and vise versa.
21d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen *
22d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen * @hide
23d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen */
24d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjenpublic final class ByteStringUtils {
25f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    private static final char[] HEX_LOWERCASE_ARRAY = "0123456789abcdef".toCharArray();
26f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    private static final char[] HEX_UPPERCASE_ARRAY = "0123456789ABCDEF".toCharArray();
27d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
28f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    private ByteStringUtils() {
29d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen    /* hide constructor */
30d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen    }
31d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
32f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    /**
33f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     * Returns the hex encoded string representation of bytes.
34f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     * @param bytes Byte array to encode.
35f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     * @return Hex encoded string representation of bytes.
36f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     */
37f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    public static String toHexString(byte[] bytes) {
38f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
39f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            return null;
40f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        }
41d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
42f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        final int byteLength = bytes.length;
43f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        final int charCount = 2 * byteLength;
44f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        final char[] chars = new char[charCount];
45d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
46f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        for (int i = 0; i < byteLength; i++) {
47f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            final int byteHex = bytes[i] & 0xFF;
48f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            chars[i * 2] = HEX_UPPERCASE_ARRAY[byteHex >>> 4];
49f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            chars[i * 2 + 1] = HEX_UPPERCASE_ARRAY[byteHex & 0x0F];
50f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        }
51f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        return new String(chars);
52d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen    }
53d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
54f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    /**
55f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     * Returns the decoded byte array representation of str.
56f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     * @param str Hex encoded string to decode.
57f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     * @return Decoded byte array representation of str.
58f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman     */
59f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    public static byte[] fromHexToByteArray(String str) {
60f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        if (str == null || str.length() == 0 || str.length() % 2 != 0) {
61f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            return null;
62f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        }
63f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman
64f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        final char[] chars = str.toCharArray();
65f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        final int charLength = chars.length;
66f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        final byte[] bytes = new byte[charLength / 2];
67d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
68f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        for (int i = 0; i < bytes.length; i++) {
69f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            bytes[i] =
70f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman                    (byte) (((getIndex(chars[i * 2]) << 4) & 0xF0)
71f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman                            | (getIndex(chars[i * 2 + 1]) & 0x0F));
72f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        }
73f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        return bytes;
74d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen    }
75d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen
76f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman    private static int getIndex(char c) {
77f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        for (int i = 0; i < HEX_UPPERCASE_ARRAY.length; i++) {
78f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            if (HEX_UPPERCASE_ARRAY[i] == c || HEX_LOWERCASE_ARRAY[i] == c) {
79f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman                return i;
80f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman            }
81f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        }
82f27d080d1aa101fa4407d2b3ec6b4d1a4a0e5787Dan Cashman        return -1;
83d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen    }
84d891f01d96cbaa3b1329c3d476084f3fedb30a89Mark Rathjen}
85