1 /* 2 * Copyright (C) 2007 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.dx.util; 18 19 /** 20 * Utilities for formatting numbers as hexadecimal. 21 */ 22 public final class Hex { 23 /** 24 * This class is uninstantiable. 25 */ 26 private Hex() { 27 // This space intentionally left blank. 28 } 29 30 /** 31 * Formats a {@code long} as an 8-byte unsigned hex value. 32 * 33 * @param v value to format 34 * @return {@code non-null;} formatted form 35 */ 36 public static String u8(long v) { 37 char[] result = new char[16]; 38 for (int i = 0; i < 16; i++) { 39 result[15 - i] = Character.forDigit((int) v & 0x0f, 16); 40 v >>= 4; 41 } 42 43 return new String(result); 44 } 45 46 /** 47 * Formats an {@code int} as a 4-byte unsigned hex value. 48 * 49 * @param v value to format 50 * @return {@code non-null;} formatted form 51 */ 52 public static String u4(int v) { 53 char[] result = new char[8]; 54 for (int i = 0; i < 8; i++) { 55 result[7 - i] = Character.forDigit(v & 0x0f, 16); 56 v >>= 4; 57 } 58 59 return new String(result); 60 } 61 62 /** 63 * Formats an {@code int} as a 3-byte unsigned hex value. 64 * 65 * @param v value to format 66 * @return {@code non-null;} formatted form 67 */ 68 public static String u3(int v) { 69 char[] result = new char[6]; 70 for (int i = 0; i < 6; i++) { 71 result[5 - i] = Character.forDigit(v & 0x0f, 16); 72 v >>= 4; 73 } 74 75 return new String(result); 76 } 77 78 /** 79 * Formats an {@code int} as a 2-byte unsigned hex value. 80 * 81 * @param v value to format 82 * @return {@code non-null;} formatted form 83 */ 84 public static String u2(int v) { 85 char[] result = new char[4]; 86 for (int i = 0; i < 4; i++) { 87 result[3 - i] = Character.forDigit(v & 0x0f, 16); 88 v >>= 4; 89 } 90 91 return new String(result); 92 } 93 94 /** 95 * Formats an {@code int} as either a 2-byte unsigned hex value 96 * (if the value is small enough) or a 4-byte unsigned hex value (if 97 * not). 98 * 99 * @param v value to format 100 * @return {@code non-null;} formatted form 101 */ 102 public static String u2or4(int v) { 103 if (v == (char) v) { 104 return u2(v); 105 } else { 106 return u4(v); 107 } 108 } 109 110 /** 111 * Formats an {@code int} as a 1-byte unsigned hex value. 112 * 113 * @param v value to format 114 * @return {@code non-null;} formatted form 115 */ 116 public static String u1(int v) { 117 char[] result = new char[2]; 118 for (int i = 0; i < 2; i++) { 119 result[1 - i] = Character.forDigit(v & 0x0f, 16); 120 v >>= 4; 121 } 122 123 return new String(result); 124 } 125 126 /** 127 * Formats an {@code int} as a 4-bit unsigned hex nibble. 128 * 129 * @param v value to format 130 * @return {@code non-null;} formatted form 131 */ 132 public static String uNibble(int v) { 133 char[] result = new char[1]; 134 135 result[0] = Character.forDigit(v & 0x0f, 16); 136 return new String(result); 137 } 138 139 /** 140 * Formats a {@code long} as an 8-byte signed hex value. 141 * 142 * @param v value to format 143 * @return {@code non-null;} formatted form 144 */ 145 public static String s8(long v) { 146 char[] result = new char[17]; 147 148 if (v < 0) { 149 result[0] = '-'; 150 v = -v; 151 } else { 152 result[0] = '+'; 153 } 154 155 for (int i = 0; i < 16; i++) { 156 result[16 - i] = Character.forDigit((int) v & 0x0f, 16); 157 v >>= 4; 158 } 159 160 return new String(result); 161 } 162 163 /** 164 * Formats an {@code int} as a 4-byte signed hex value. 165 * 166 * @param v value to format 167 * @return {@code non-null;} formatted form 168 */ 169 public static String s4(int v) { 170 char[] result = new char[9]; 171 172 if (v < 0) { 173 result[0] = '-'; 174 v = -v; 175 } else { 176 result[0] = '+'; 177 } 178 179 for (int i = 0; i < 8; i++) { 180 result[8 - i] = Character.forDigit(v & 0x0f, 16); 181 v >>= 4; 182 } 183 184 return new String(result); 185 } 186 187 /** 188 * Formats an {@code int} as a 2-byte signed hex value. 189 * 190 * @param v value to format 191 * @return {@code non-null;} formatted form 192 */ 193 public static String s2(int v) { 194 char[] result = new char[5]; 195 196 if (v < 0) { 197 result[0] = '-'; 198 v = -v; 199 } else { 200 result[0] = '+'; 201 } 202 203 for (int i = 0; i < 4; i++) { 204 result[4 - i] = Character.forDigit(v & 0x0f, 16); 205 v >>= 4; 206 } 207 208 return new String(result); 209 } 210 211 /** 212 * Formats an {@code int} as a 1-byte signed hex value. 213 * 214 * @param v value to format 215 * @return {@code non-null;} formatted form 216 */ 217 public static String s1(int v) { 218 char[] result = new char[3]; 219 220 if (v < 0) { 221 result[0] = '-'; 222 v = -v; 223 } else { 224 result[0] = '+'; 225 } 226 227 for (int i = 0; i < 2; i++) { 228 result[2 - i] = Character.forDigit(v & 0x0f, 16); 229 v >>= 4; 230 } 231 232 return new String(result); 233 } 234 235 /** 236 * Formats a hex dump of a portion of a {@code byte[]}. The result 237 * is always newline-terminated, unless the passed-in length was zero, 238 * in which case the result is always the empty string ({@code ""}). 239 * 240 * @param arr {@code non-null;} array to format 241 * @param offset {@code >= 0;} offset to the part to dump 242 * @param length {@code >= 0;} number of bytes to dump 243 * @param outOffset {@code >= 0;} first output offset to print 244 * @param bpl {@code >= 0;} number of bytes of output per line 245 * @param addressLength {@code {2,4,6,8};} number of characters for each address 246 * header 247 * @return {@code non-null;} a string of the dump 248 */ 249 public static String dump(byte[] arr, int offset, int length, 250 int outOffset, int bpl, int addressLength) { 251 int end = offset + length; 252 253 // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0) 254 if (((offset | length | end) < 0) || (end > arr.length)) { 255 throw new IndexOutOfBoundsException("arr.length " + 256 arr.length + "; " + 257 offset + "..!" + end); 258 } 259 260 if (outOffset < 0) { 261 throw new IllegalArgumentException("outOffset < 0"); 262 } 263 264 if (length == 0) { 265 return ""; 266 } 267 268 StringBuffer sb = new StringBuffer(length * 4 + 6); 269 boolean bol = true; 270 int col = 0; 271 272 while (length > 0) { 273 if (col == 0) { 274 String astr; 275 switch (addressLength) { 276 case 2: astr = Hex.u1(outOffset); break; 277 case 4: astr = Hex.u2(outOffset); break; 278 case 6: astr = Hex.u3(outOffset); break; 279 default: astr = Hex.u4(outOffset); break; 280 } 281 sb.append(astr); 282 sb.append(": "); 283 } else if ((col & 1) == 0) { 284 sb.append(' '); 285 } 286 sb.append(Hex.u1(arr[offset])); 287 outOffset++; 288 offset++; 289 col++; 290 if (col == bpl) { 291 sb.append('\n'); 292 col = 0; 293 } 294 length--; 295 } 296 297 if (col != 0) { 298 sb.append('\n'); 299 } 300 301 return sb.toString(); 302 } 303 } 304