1 /*
2  * Copyright (C) 2021 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 com.android.net.module.util;
18 
19 import androidx.annotation.Nullable;
20 
21 /**
22  * Hex utility functions.
23  *
24  * @hide
25  */
26 public class HexDump {
27     private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
28             'A', 'B', 'C', 'D', 'E', 'F' };
29     private static final char[] HEX_LOWER_CASE_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7',
30             '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
31 
32     /**
33      * Dump the hex string corresponding to the specified byte array.
34      *
35      * @param array byte array to be dumped.
36      */
dumpHexString(@ullable byte[] array)37     public static String dumpHexString(@Nullable byte[] array) {
38         if (array == null) return "(null)";
39         return dumpHexString(array, 0, array.length);
40     }
41 
42     /**
43      * Dump the hex string corresponding to the specified byte array.
44      *
45      * @param array byte array to be dumped.
46      * @param offset the offset in array where dump should start.
47      * @param length the length of bytes to be dumped.
48      */
dumpHexString(@ullable byte[] array, int offset, int length)49     public static String dumpHexString(@Nullable byte[] array, int offset, int length) {
50         if (array == null) return "(null)";
51         StringBuilder result = new StringBuilder();
52 
53         byte[] line = new byte[16];
54         int lineIndex = 0;
55 
56         result.append("\n0x");
57         result.append(toHexString(offset));
58 
59         for (int i = offset; i < offset + length; i++) {
60             if (lineIndex == 16) {
61                 result.append(" ");
62 
63                 for (int j = 0; j < 16; j++) {
64                     if (line[j] > ' ' && line[j] < '~') {
65                         result.append(new String(line, j, 1));
66                     } else {
67                         result.append(".");
68                     }
69                 }
70 
71                 result.append("\n0x");
72                 result.append(toHexString(i));
73                 lineIndex = 0;
74             }
75 
76             byte b = array[i];
77             result.append(" ");
78             result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
79             result.append(HEX_DIGITS[b & 0x0F]);
80 
81             line[lineIndex++] = b;
82         }
83 
84         if (lineIndex != 16) {
85             int count = (16 - lineIndex) * 3;
86             count++;
87             for (int i = 0; i < count; i++) {
88                 result.append(" ");
89             }
90 
91             for (int i = 0; i < lineIndex; i++) {
92                 if (line[i] > ' ' && line[i] < '~') {
93                     result.append(new String(line, i, 1));
94                 } else {
95                     result.append(".");
96                 }
97             }
98         }
99 
100         return result.toString();
101     }
102 
103     /**
104      * Convert a byte to an uppercase hex string.
105      *
106      * @param b the byte to be converted.
107      */
toHexString(byte b)108     public static String toHexString(byte b) {
109         return toHexString(toByteArray(b));
110     }
111 
112     /**
113      * Convert a byte array to an uppercase hex string.
114      *
115      * @param array the byte array to be converted.
116      */
toHexString(byte[] array)117     public static String toHexString(byte[] array) {
118         return toHexString(array, 0, array.length, true);
119     }
120 
121     /**
122      * Convert a byte array to a hex string.
123      *
124      * @param array the byte array to be converted.
125      * @param upperCase whether the converted hex string should be uppercase or not.
126      */
toHexString(byte[] array, boolean upperCase)127     public static String toHexString(byte[] array, boolean upperCase) {
128         return toHexString(array, 0, array.length, upperCase);
129     }
130 
131     /**
132      * Convert a byte array to hex string.
133      *
134      * @param array the byte array to be converted.
135      * @param offset the offset in array where conversion should start.
136      * @param length the length of bytes to be converted.
137      */
toHexString(byte[] array, int offset, int length)138     public static String toHexString(byte[] array, int offset, int length) {
139         return toHexString(array, offset, length, true);
140     }
141 
142     /**
143      * Convert a byte array to hex string.
144      *
145      * @param array the byte array to be converted.
146      * @param offset the offset in array where conversion should start.
147      * @param length the length of bytes to be converted.
148      * @param upperCase whether the converted hex string should be uppercase or not.
149      */
toHexString(byte[] array, int offset, int length, boolean upperCase)150     public static String toHexString(byte[] array, int offset, int length, boolean upperCase) {
151         char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS;
152         char[] buf = new char[length * 2];
153 
154         int bufIndex = 0;
155         for (int i = offset; i < offset + length; i++) {
156             byte b = array[i];
157             buf[bufIndex++] = digits[(b >>> 4) & 0x0F];
158             buf[bufIndex++] = digits[b & 0x0F];
159         }
160 
161         return new String(buf);
162     }
163 
164     /**
165      * Convert an integer to hex string.
166      *
167      * @param i the integer to be converted.
168      */
toHexString(int i)169     public static String toHexString(int i) {
170         return toHexString(toByteArray(i));
171     }
172 
173     /**
174      * Convert a byte to byte array.
175      *
176      * @param b the byte to be converted.
177      */
toByteArray(byte b)178     public static byte[] toByteArray(byte b) {
179         byte[] array = new byte[1];
180         array[0] = b;
181         return array;
182     }
183 
184     /**
185      * Convert an integer to byte array.
186      *
187      * @param i the integer to be converted.
188      */
toByteArray(int i)189     public static byte[] toByteArray(int i) {
190         byte[] array = new byte[4];
191 
192         array[3] = (byte) (i & 0xFF);
193         array[2] = (byte) ((i >> 8) & 0xFF);
194         array[1] = (byte) ((i >> 16) & 0xFF);
195         array[0] = (byte) ((i >> 24) & 0xFF);
196 
197         return array;
198     }
199 
toByte(char c)200     private static int toByte(char c) {
201         if (c >= '0' && c <= '9') return (c - '0');
202         if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
203         if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
204 
205         throw new RuntimeException("Invalid hex char '" + c + "'");
206     }
207 
208     /**
209      * Convert a hex string to a byte array.
210      *
211      * @param hexString the string to be converted.
212      */
hexStringToByteArray(String hexString)213     public static byte[] hexStringToByteArray(String hexString) {
214         int length = hexString.length();
215         byte[] buffer = new byte[length / 2];
216 
217         for (int i = 0; i < length; i += 2) {
218             buffer[i / 2] =
219                     (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));
220         }
221 
222         return buffer;
223     }
224 
225     /**
226      * Convert a byte to hex string and append it to StringBuilder.
227      *
228      * @param sb StringBuilder instance.
229      * @param b the byte to be converted.
230      * @param upperCase whether the converted hex string should be uppercase or not.
231      */
appendByteAsHex(StringBuilder sb, byte b, boolean upperCase)232     public static StringBuilder appendByteAsHex(StringBuilder sb, byte b, boolean upperCase) {
233         char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS;
234         sb.append(digits[(b >> 4) & 0xf]);
235         sb.append(digits[b & 0xf]);
236         return sb;
237     }
238 }
239