--- /dev/null
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.util;
+
+/**
+ * Utilities for formatting numbers as hexadecimal.
+ */
+public final class Hex {
+ /**
+ * This class is uninstantiable.
+ */
+ private Hex() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Formats a {@code long} as an 8-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u8(long v) {
+ char[] result = new char[16];
+ for (int i = 0; i < 16; i++) {
+ result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 4-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u4(int v) {
+ char[] result = new char[8];
+ for (int i = 0; i < 8; i++) {
+ result[7 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 3-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u3(int v) {
+ char[] result = new char[6];
+ for (int i = 0; i < 6; i++) {
+ result[5 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 2-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u2(int v) {
+ char[] result = new char[4];
+ for (int i = 0; i < 4; i++) {
+ result[3 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as either a 2-byte unsigned hex value
+ * (if the value is small enough) or a 4-byte unsigned hex value (if
+ * not).
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u2or4(int v) {
+ if (v == (char) v) {
+ return u2(v);
+ } else {
+ return u4(v);
+ }
+ }
+
+ /**
+ * Formats an {@code int} as a 1-byte unsigned hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String u1(int v) {
+ char[] result = new char[2];
+ for (int i = 0; i < 2; i++) {
+ result[1 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 4-bit unsigned hex nibble.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String uNibble(int v) {
+ char[] result = new char[1];
+
+ result[0] = Character.forDigit(v & 0x0f, 16);
+ return new String(result);
+ }
+
+ /**
+ * Formats a {@code long} as an 8-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s8(long v) {
+ char[] result = new char[17];
+
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
+ }
+
+ for (int i = 0; i < 16; i++) {
+ result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 4-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s4(int v) {
+ char[] result = new char[9];
+
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
+ }
+
+ for (int i = 0; i < 8; i++) {
+ result[8 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 2-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s2(int v) {
+ char[] result = new char[5];
+
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
+ }
+
+ for (int i = 0; i < 4; i++) {
+ result[4 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats an {@code int} as a 1-byte signed hex value.
+ *
+ * @param v value to format
+ * @return {@code non-null;} formatted form
+ */
+ public static String s1(int v) {
+ char[] result = new char[3];
+
+ if (v < 0) {
+ result[0] = '-';
+ v = -v;
+ } else {
+ result[0] = '+';
+ }
+
+ for (int i = 0; i < 2; i++) {
+ result[2 - i] = Character.forDigit(v & 0x0f, 16);
+ v >>= 4;
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Formats a hex dump of a portion of a {@code byte[]}. The result
+ * is always newline-terminated, unless the passed-in length was zero,
+ * in which case the result is always the empty string ({@code ""}).
+ *
+ * @param arr {@code non-null;} array to format
+ * @param offset {@code >= 0;} offset to the part to dump
+ * @param length {@code >= 0;} number of bytes to dump
+ * @param outOffset {@code >= 0;} first output offset to print
+ * @param bpl {@code >= 0;} number of bytes of output per line
+ * @param addressLength {@code {2,4,6,8};} number of characters for each address
+ * header
+ * @return {@code non-null;} a string of the dump
+ */
+ public static String dump(byte[] arr, int offset, int length,
+ int outOffset, int bpl, int addressLength) {
+ int end = offset + length;
+
+ // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
+ if (((offset | length | end) < 0) || (end > arr.length)) {
+ throw new IndexOutOfBoundsException("arr.length " +
+ arr.length + "; " +
+ offset + "..!" + end);
+ }
+
+ if (outOffset < 0) {
+ throw new IllegalArgumentException("outOffset < 0");
+ }
+
+ if (length == 0) {
+ return "";
+ }
+
+ StringBuffer sb = new StringBuffer(length * 4 + 6);
+ boolean bol = true;
+ int col = 0;
+
+ while (length > 0) {
+ if (col == 0) {
+ String astr;
+ switch (addressLength) {
+ case 2: astr = Hex.u1(outOffset); break;
+ case 4: astr = Hex.u2(outOffset); break;
+ case 6: astr = Hex.u3(outOffset); break;
+ default: astr = Hex.u4(outOffset); break;
+ }
+ sb.append(astr);
+ sb.append(": ");
+ } else if ((col & 1) == 0) {
+ sb.append(' ');
+ }
+ sb.append(Hex.u1(arr[offset]));
+ outOffset++;
+ offset++;
+ col++;
+ if (col == bpl) {
+ sb.append('\n');
+ col = 0;
+ }
+ length--;
+ }
+
+ if (col != 0) {
+ sb.append('\n');
+ }
+
+ return sb.toString();
+ }
+}