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