Home | History | Annotate | Download | only in util
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2010 Ben Gruver (JesusFreke)
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 package org.jf.util;
     30 
     31 /**
     32  * Utilities for formatting numbers as hexadecimal.
     33  */
     34 public final class Hex {
     35     /**
     36      * This class is uninstantiable.
     37      */
     38     private Hex() {
     39         // This space intentionally left blank.
     40     }
     41 
     42     /**
     43      * Formats a <code>long</code> as an 8-byte unsigned hex value.
     44      *
     45      * @param v value to format
     46      * @return non-null; formatted form
     47      */
     48     public static String u8(long v) {
     49         char[] result = new char[16];
     50         for (int i = 0; i < 16; i++) {
     51             result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
     52             v >>= 4;
     53         }
     54 
     55         return new String(result);
     56     }
     57 
     58     /**
     59      * Formats an <code>int</code> as a 4-byte unsigned hex value.
     60      *
     61      * @param v value to format
     62      * @return non-null; formatted form
     63      */
     64     public static String u4(int v) {
     65         char[] result = new char[8];
     66         for (int i = 0; i < 8; i++) {
     67             result[7 - i] = Character.forDigit(v & 0x0f, 16);
     68             v >>= 4;
     69         }
     70 
     71         return new String(result);
     72     }
     73 
     74     /**
     75      * Formats an <code>int</code> as a 3-byte unsigned hex value.
     76      *
     77      * @param v value to format
     78      * @return non-null; formatted form
     79      */
     80     public static String u3(int v) {
     81         char[] result = new char[6];
     82         for (int i = 0; i < 6; i++) {
     83             result[5 - i] = Character.forDigit(v & 0x0f, 16);
     84             v >>= 4;
     85         }
     86 
     87         return new String(result);
     88     }
     89 
     90     /**
     91      * Formats an <code>int</code> as a 2-byte unsigned hex value.
     92      *
     93      * @param v value to format
     94      * @return non-null; formatted form
     95      */
     96     public static String u2(int v) {
     97         char[] result = new char[4];
     98         for (int i = 0; i < 4; i++) {
     99             result[3 - i] = Character.forDigit(v & 0x0f, 16);
    100             v >>= 4;
    101         }
    102 
    103         return new String(result);
    104     }
    105 
    106     /**
    107      * Formats an <code>int</code> as either a 2-byte unsigned hex value
    108      * (if the value is small enough) or a 4-byte unsigned hex value (if
    109      * not).
    110      *
    111      * @param v value to format
    112      * @return non-null; formatted form
    113      */
    114     public static String u2or4(int v) {
    115         if (v == (char) v) {
    116             return u2(v);
    117         } else {
    118             return u4(v);
    119         }
    120     }
    121 
    122     /**
    123      * Formats an <code>int</code> as a 1-byte unsigned hex value.
    124      *
    125      * @param v value to format
    126      * @return non-null; formatted form
    127      */
    128     public static String u1(int v) {
    129         char[] result = new char[2];
    130         for (int i = 0; i < 2; i++) {
    131             result[1 - i] = Character.forDigit(v & 0x0f, 16);
    132             v >>= 4;
    133         }
    134 
    135         return new String(result);
    136     }
    137 
    138     /**
    139      * Formats an <code>int</code> as a 4-bit unsigned hex nibble.
    140      *
    141      * @param v value to format
    142      * @return non-null; formatted form
    143      */
    144     public static String uNibble(int v) {
    145         char[] result = new char[1];
    146 
    147         result[0] = Character.forDigit(v & 0x0f, 16);
    148         return new String(result);
    149     }
    150 
    151     /**
    152      * Formats a <code>long</code> as an 8-byte signed hex value.
    153      *
    154      * @param v value to format
    155      * @return non-null; formatted form
    156      */
    157     public static String s8(long v) {
    158         char[] result = new char[17];
    159 
    160         if (v < 0) {
    161             result[0] = '-';
    162             v = -v;
    163         } else {
    164             result[0] = '+';
    165         }
    166 
    167         for (int i = 0; i < 16; i++) {
    168             result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
    169             v >>= 4;
    170         }
    171 
    172         return new String(result);
    173     }
    174 
    175     /**
    176      * Formats an <code>int</code> as a 4-byte signed hex value.
    177      *
    178      * @param v value to format
    179      * @return non-null; formatted form
    180      */
    181     public static String s4(int v) {
    182         char[] result = new char[9];
    183 
    184         if (v < 0) {
    185             result[0] = '-';
    186             v = -v;
    187         } else {
    188             result[0] = '+';
    189         }
    190 
    191         for (int i = 0; i < 8; i++) {
    192             result[8 - i] = Character.forDigit(v & 0x0f, 16);
    193             v >>= 4;
    194         }
    195 
    196         return new String(result);
    197     }
    198 
    199     /**
    200      * Formats an <code>int</code> as a 2-byte signed hex value.
    201      *
    202      * @param v value to format
    203      * @return non-null; formatted form
    204      */
    205     public static String s2(int v) {
    206         char[] result = new char[5];
    207 
    208         if (v < 0) {
    209             result[0] = '-';
    210             v = -v;
    211         } else {
    212             result[0] = '+';
    213         }
    214 
    215         for (int i = 0; i < 4; i++) {
    216             result[4 - i] = Character.forDigit(v & 0x0f, 16);
    217             v >>= 4;
    218         }
    219 
    220         return new String(result);
    221     }
    222 
    223     /**
    224      * Formats an <code>int</code> as a 1-byte signed hex value.
    225      *
    226      * @param v value to format
    227      * @return non-null; formatted form
    228      */
    229     public static String s1(int v) {
    230         char[] result = new char[3];
    231 
    232         if (v < 0) {
    233             result[0] = '-';
    234             v = -v;
    235         } else {
    236             result[0] = '+';
    237         }
    238 
    239         for (int i = 0; i < 2; i++) {
    240             result[2 - i] = Character.forDigit(v & 0x0f, 16);
    241             v >>= 4;
    242         }
    243 
    244         return new String(result);
    245     }
    246 
    247     /**
    248      * Formats a hex dump of a portion of a <code>byte[]</code>. The result
    249      * is always newline-terminated, unless the passed-in length was zero,
    250      * in which case the result is always the empty string (<code>""</code>).
    251      *
    252      * @param arr non-null; array to format
    253      * @param offset &gt;= 0; offset to the part to dump
    254      * @param length &gt;= 0; number of bytes to dump
    255      * @param outOffset &gt;= 0; first output offset to print
    256      * @param bpl &gt;= 0; number of bytes of output per line
    257      * @param addressLength {2,4,6,8}; number of characters for each address
    258      * header
    259      * @return non-null; a string of the dump
    260      */
    261     public static String dump(byte[] arr, int offset, int length,
    262                               int outOffset, int bpl, int addressLength) {
    263         int end = offset + length;
    264 
    265         // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
    266         if (((offset | length | end) < 0) || (end > arr.length)) {
    267             throw new IndexOutOfBoundsException("arr.length " +
    268                                                 arr.length + "; " +
    269                                                 offset + "..!" + end);
    270         }
    271 
    272         if (outOffset < 0) {
    273             throw new IllegalArgumentException("outOffset < 0");
    274         }
    275 
    276         if (length == 0) {
    277             return "";
    278         }
    279 
    280         StringBuffer sb = new StringBuffer(length * 4 + 6);
    281         boolean bol = true;
    282         int col = 0;
    283 
    284         while (length > 0) {
    285             if (col == 0) {
    286                 String astr;
    287                 switch (addressLength) {
    288                     case 2:  astr = Hex.u1(outOffset); break;
    289                     case 4:  astr = Hex.u2(outOffset); break;
    290                     case 6:  astr = Hex.u3(outOffset); break;
    291                     default: astr = Hex.u4(outOffset); break;
    292                 }
    293                 sb.append(astr);
    294                 sb.append(": ");
    295             } else if ((col & 1) == 0) {
    296                 sb.append(' ');
    297             }
    298             sb.append(Hex.u1(arr[offset]));
    299             outOffset++;
    300             offset++;
    301             col++;
    302             if (col == bpl) {
    303                 sb.append('\n');
    304                 col = 0;
    305             }
    306             length--;
    307         }
    308 
    309         if (col != 0) {
    310             sb.append('\n');
    311         }
    312 
    313         return sb.toString();
    314     }
    315 }