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      */
Hex()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      */
u8(long v)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      */
u4(int v)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      */
u3(int v)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      */
u2(int v)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      */
u2or4(int v)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      */
u1(int v)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      */
uNibble(int v)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      */
s8(long v)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      */
s4(int v)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      */
s2(int v)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      */
s1(int v)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      */
dump(byte[] arr, int offset, int length, int outOffset, int bpl, int addressLength)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