Project Report: fawkez

Packagesummary org.jcoderz.commons.util

org.jcoderz.commons.util.HexUtil

LineHitsNoteSource
1  /*
2   * $Id: HexUtil.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. 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 are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons.util;
34  
35  import java.util.Arrays;
36  
37  /**
38   * This class converts byte array data from and to hex and also provides
39   * a hexdump method.
40   *
41   * @author Albrecht Messner
42   */
43  public final class HexUtil
44  {
45     private static final int BYTE_UNSIGNED_MAX = 255;
46     private static final int HALF_BYTE = 4;
47     private static final byte LOW_HALF_MASK = (byte) 0x0F;
48     private static final byte HIGH_HALF_MASK = (byte) 0xF0;
49     private static final int BYTE_MASK = 0xFF;
50     private static final int CHARS_PER_BYTE = 2;
51     private static final int DECIMAL_OFFSET = 10;
52  
53  
54100    private static final char[] HEX_CHARS = {
55        '0', '1', '2', '3', '4', '5', '6', '7',
56        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
57     };
58  
59100    private static final String[] BYTE_AS_HEX
60           = new String[BYTE_UNSIGNED_MAX + 1];
61  
62100    private static final int[] CHAR_TO_NIBBLE_LOW
63           = new int[BYTE_UNSIGNED_MAX + 1];
64100    private static final int[] CHAR_TO_NIBBLE_HIGH
65           = new int[BYTE_UNSIGNED_MAX + 1];
66  
67     private static final int DUMP_BYTES_PER_LINE = 16;
68     private static final int DUMP_BYTES_PER_COLUMN = 8;
69     private static final int DUMP_ADDR_LEN = 8;
70     private static final int DUMP_BUFFER_SIZE = DUMP_ADDR_LEN // address
71           + DUMP_BYTES_PER_LINE * CHARS_PER_BYTE // bytes
72           + DUMP_BYTES_PER_LINE // whitespaces between bytes
73           + 1 + 1; // extra whitespace after address and to separate columns
74  
75     static
76     {
77        // set up tables/arrays for byte to hex conversion
78100       final StringBuffer sb = new StringBuffer();
79100       for (int i = 0; i < BYTE_AS_HEX.length; i++)
80        {
81100          sb.setLength(0);
82100          final int lowerFourBits = i & LOW_HALF_MASK;
83100          final int highFourBits = (i & HIGH_HALF_MASK) >> HALF_BYTE;
84100          sb.append(HEX_CHARS[highFourBits]);
85100          sb.append(HEX_CHARS[lowerFourBits]);
86100          BYTE_AS_HEX[i] = sb.toString();
87        }
88  
89        // set up tables/arrays for hex to byte conversion
90100       Arrays.fill(CHAR_TO_NIBBLE_LOW, -1);
91100       Arrays.fill(CHAR_TO_NIBBLE_HIGH, -1);
92100       for (int i = '0'; i <= '9'; i++)
93        {
94100          CHAR_TO_NIBBLE_LOW[i] = i - '0';
95100          CHAR_TO_NIBBLE_HIGH[i] = (i - '0') << HALF_BYTE;
96        }
97100       for (int i = 'a'; i <= 'f'; i++)
98        {
99100          CHAR_TO_NIBBLE_LOW[i] = i - 'a' + DECIMAL_OFFSET;
100100          CHAR_TO_NIBBLE_HIGH[i] = (i - 'a' + DECIMAL_OFFSET) << HALF_BYTE;
101        }
102100       for (int i = 'A'; i <= 'F'; i++)
103        {
104100          CHAR_TO_NIBBLE_LOW[i] = i - 'A' + DECIMAL_OFFSET;
105100          CHAR_TO_NIBBLE_HIGH[i] = (i - 'A' + DECIMAL_OFFSET) << HALF_BYTE;
106        }
107100    }
108  
109     private HexUtil ()
1100    {
111         // utility class that provides only static methods
1120    }
113  
114     /**
115      * Converts a byte array into an upper-case hex string, starting at the
116      * given offset and converting the given number of bytes.
117      * @param data the byte data to convert to hex
118      * @param offset the start offset in the byte array
119      * @param length the number of bytes to convert
120      * @return null if data was null, an empty string if data.length == 0,
121      *       and the hex representation of the byte array otherwise
122      * @throws IndexOutOfBoundsException if offset + length > data.lenght
123      */
124     public static String bytesToHex (
125           final byte[] data, final int offset, final int length)
126           throws IndexOutOfBoundsException
127     {
128        final String result;
129100       if (data == null)
130        {
131100          result = null;
132        }
133        else
134        {
135100          final StringBuffer sbuf = new StringBuffer();
136100          for (int i = offset; i < offset + length; i++)
137           {
138100             sbuf.append(BYTE_AS_HEX[data[i] & BYTE_MASK]);
139           }
140100          result = sbuf.toString();
141        }
142100       return result;
143     }
144  
145     /**
146      * Converts a byte array into an upper-case hex string, starting at the
147      * first byte and converting the whole array.
148      * @param data the byte data to convert to hex
149      * @return null if data was null, an empty string if data.length == 0,
150      *       and the hex representation of the byte array otherwise
151      */
152     public static String bytesToHex (final byte[] data)
153     {
154        final String result;
155100       if (data != null)
156        {
157100          result = bytesToHex(data, 0, data.length);
158        }
159        else
160        {
1610          result = null;
162        }
163100       return result;
164     }
165  
166     /**
167      * Convert the given hex string to a byte array.
168      * @param s the string to convert
169      * @return null if the string is null, an empty byte array if s.length == 0
170      *       and a byte array representing the hex string otherwise
171      * @throws IllegalArgumentException if the string is not a multiple of 2
172      *       characters long, or if the string contains an invalid hex char
173      */
174     public static byte[] stringToBytes (final String s)
175           throws IllegalArgumentException
176     {
177        final byte[] result;
178100       if (s == null)
179        {
1800          result = null;
181        }
182100       else if (s.length() == 0)
183        {
1840          result = new byte[0];
185        }
186        else
187        {
188           // string must be a multiple of 2 chars
189100          if (s.length() % CHARS_PER_BYTE != 0)
190           {
191100             throw new IllegalArgumentException(
192                    "The length of a hex string must be a multiple of 2 (was "
193                    + s.length() + ")");
194           }
195100          int count = 0;
196100          result = new byte[s.length() / CHARS_PER_BYTE];
197           try
198           {
199100             for (int i = 0; i < s.length(); i++)
200              {
201100                final char c1 = s.charAt(i);
202100                final char c2 = s.charAt(++i);
203100                final int b = CHAR_TO_NIBBLE_HIGH[c1] | CHAR_TO_NIBBLE_LOW[c2];
204100                if (b == -1)
205                 {
206100                   throw new IllegalArgumentException(
207                          "'" + c1 + c2
208                          + "' is not a valid hex representation of a byte");
209                 }
210100                result[count] = (byte) b;
211100                ++count;
212              }
213           }
2140          catch (IndexOutOfBoundsException ex)
215           {
2160             final char c1 = s.charAt(count * CHARS_PER_BYTE);
2170             final char c2 = s.charAt(count * CHARS_PER_BYTE + 1);
2180             final IllegalArgumentException e = new IllegalArgumentException(
219                    "'" + c1 + c2
220                    + "' is not a valid hex representation of a byte");
2210             e.initCause(ex);
2220             throw e;
223100          }
224        }
225100       return result;
226     }
227  
228     /**
229      * Produces a hexdump of the given byte array with a formatting
230      * as in "hexdump -C" (canonical hex + ASCII display). This formatting
231      * contains an address column, sixteen bytes of hex separated by spaces,
232      * with an extra space after eight bytes, and an ascii print-out of the
233      * bytes enclosed in pipe symbols. Non-ASCII characters are replaced by
234      * dots.
235      *
236      * @param data the byte data to dump
237      * @return a string containing the hexdump, or null if data was null
238      */
239     public static String dump (final byte[] data)
240     {
241        final String result;
242100       if (data == null)
243        {
244100          result = null;
245        }
246        else
247        {
248100          int offset = 0;
249100          final StringBuffer dumpBuffer = new StringBuffer();
250100          final StringBuffer lineBuffer = new StringBuffer();
251100          final StringBuffer charBuffer = new StringBuffer();
252100          while (offset < data.length)
253           {
254100             lineBuffer.setLength(0);
255100             charBuffer.setLength(0);
256100             charBuffer.append('|');
257100             lineBuffer.append(offsetToHex(offset));
258100             lineBuffer.append(' ');
259100             final int end = (offset + DUMP_BYTES_PER_LINE < data.length
260                    ? offset + DUMP_BYTES_PER_LINE
261                    : data.length);
262100             for (int i = offset; i < end; i++)
263              {
264100                final byte b = data[i];
265100                lineBuffer.append(bytesToHex(new byte[] {b}));
266100                lineBuffer.append(' ');
267  
268100                if (i - offset == DUMP_BYTES_PER_COLUMN - 1)
269                 {
270100                   lineBuffer.append(' ');
271                 }
272100                final char c = (char) b;
273100                if ((! Character.isISOControl(c))
274                       && StringUtil.isAscii(c))
275                 {
276100                   charBuffer.append(c);
277                 }
278                 else
279                 {
280100                   charBuffer.append('.');
281                 }
282              }
283100             padBuffer(lineBuffer);
284100             charBuffer.append('|');
285100             dumpBuffer.append(lineBuffer);
286100             dumpBuffer.append(charBuffer);
287100             dumpBuffer.append(Constants.LINE_SEPARATOR);
288100             offset += DUMP_BYTES_PER_LINE;
289100          }
290100          result = dumpBuffer.toString();
291        }
292100       return result;
293     }
294  
295     private static void padBuffer (final StringBuffer sbuf)
296     {
297100       while (sbuf.length() < DUMP_BUFFER_SIZE)
298        {
299100          sbuf.append(' ');
300        }
301100    }
302  
303     private static String offsetToHex (int offset)
304     {
305100       String s = Integer.toHexString(offset);
306100       while (s.length() < DUMP_ADDR_LEN)
307        {
308100(1)         s = "0" + s;
309        }
310100       return s;
311     }
312  }

Findings in this File

c (1) 308 : 10 Prefer StringBuffer over += for concatenating strings