1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.util;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Utilities for formatting numbers as hexadecimal.
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class Hex {
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * This class is uninstantiable.
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private Hex() {
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // This space intentionally left blank.
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats a {@code long} as an 8-byte unsigned hex value.
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String u8(long v) {
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[16];
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 16; i++) {
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 4-byte unsigned hex value.
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String u4(int v) {
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[8];
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 8; i++) {
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[7 - i] = Character.forDigit(v & 0x0f, 16);
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 3-byte unsigned hex value.
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String u3(int v) {
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[6];
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 6; i++) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[5 - i] = Character.forDigit(v & 0x0f, 16);
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 2-byte unsigned hex value.
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String u2(int v) {
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[4];
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 4; i++) {
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[3 - i] = Character.forDigit(v & 0x0f, 16);
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as either a 2-byte unsigned hex value
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * (if the value is small enough) or a 4-byte unsigned hex value (if
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * not).
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String u2or4(int v) {
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (v == (char) v) {
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return u2(v);
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return u4(v);
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 1-byte unsigned hex value.
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String u1(int v) {
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[2];
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 2; i++) {
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[1 - i] = Character.forDigit(v & 0x0f, 16);
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 4-bit unsigned hex nibble.
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String uNibble(int v) {
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[1];
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result[0] = Character.forDigit(v & 0x0f, 16);
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats a {@code long} as an 8-byte signed hex value.
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String s8(long v) {
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[17];
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (v < 0) {
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '-';
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v = -v;
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '+';
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 16; i++) {
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 4-byte signed hex value.
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String s4(int v) {
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[9];
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (v < 0) {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '-';
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v = -v;
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '+';
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 8; i++) {
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[8 - i] = Character.forDigit(v & 0x0f, 16);
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 2-byte signed hex value.
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String s2(int v) {
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[5];
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (v < 0) {
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '-';
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v = -v;
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '+';
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 4; i++) {
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[4 - i] = Character.forDigit(v & 0x0f, 16);
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats an {@code int} as a 1-byte signed hex value.
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param v value to format
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} formatted form
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String s1(int v) {
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        char[] result = new char[3];
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (v < 0) {
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '-';
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v = -v;
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[0] = '+';
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < 2; i++) {
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result[2 - i] = Character.forDigit(v & 0x0f, 16);
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            v >>= 4;
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new String(result);
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Formats a hex dump of a portion of a {@code byte[]}. The result
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is always newline-terminated, unless the passed-in length was zero,
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * in which case the result is always the empty string ({@code ""}).
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param arr {@code non-null;} array to format
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param offset {@code >= 0;} offset to the part to dump
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param length {@code >= 0;} number of bytes to dump
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param outOffset {@code >= 0;} first output offset to print
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param bpl {@code >= 0;} number of bytes of output per line
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param addressLength {@code {2,4,6,8};} number of characters for each address
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * header
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} a string of the dump
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String dump(byte[] arr, int offset, int length,
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                              int outOffset, int bpl, int addressLength) {
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int end = offset + length;
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (((offset | length | end) < 0) || (end > arr.length)) {
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IndexOutOfBoundsException("arr.length " +
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                                arr.length + "; " +
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                                offset + "..!" + end);
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (outOffset < 0) {
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("outOffset < 0");
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (length == 0) {
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "";
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(length * 4 + 6);
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean bol = true;
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int col = 0;
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        while (length > 0) {
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (col == 0) {
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                String astr;
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                switch (addressLength) {
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    case 2:  astr = Hex.u1(outOffset); break;
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    case 4:  astr = Hex.u2(outOffset); break;
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    case 6:  astr = Hex.u3(outOffset); break;
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    default: astr = Hex.u4(outOffset); break;
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(astr);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(": ");
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if ((col & 1) == 0) {
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(' ');
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(Hex.u1(arr[offset]));
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            outOffset++;
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            offset++;
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            col++;
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (col == bpl) {
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append('\n');
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                col = 0;
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            length--;
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (col != 0) {
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append('\n');
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
304