1    
2    /* ====================================================================
3     * The Apache Software License, Version 1.1
4     *
5     * Copyright (c) 2002 The Apache Software Foundation.  All rights
6     * reserved.
7     *
8     * Redistribution and use in source and binary forms, with or without
9     * modification, are permitted provided that the following conditions
10    * are met:
11    *
12    * 1. Redistributions of source code must retain the above copyright
13    *    notice, this list of conditions and the following disclaimer.
14    *
15    * 2. Redistributions in binary form must reproduce the above copyright
16    *    notice, this list of conditions and the following disclaimer in
17    *    the documentation and/or other materials provided with the
18    *    distribution.
19    *
20    * 3. The end-user documentation included with the redistribution,
21    *    if any, must include the following acknowledgment:
22    *       "This product includes software developed by the
23    *        Apache Software Foundation (http://www.apache.org/)."
24    *    Alternately, this acknowledgment may appear in the software itself,
25    *    if and wherever such third-party acknowledgments normally appear.
26    *
27    * 4. The names "Apache" and "Apache Software Foundation" and
28    *    "Apache POI" must not be used to endorse or promote products
29    *    derived from this software without prior written permission. For
30    *    written permission, please contact apache@apache.org.
31    *
32    * 5. Products derived from this software may not be called "Apache",
33    *    "Apache POI", nor may "Apache" appear in their name, without
34    *    prior written permission of the Apache Software Foundation.
35    *
36    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47    * SUCH DAMAGE.
48    * ====================================================================
49    *
50    * This software consists of voluntary contributions made by many
51    * individuals on behalf of the Apache Software Foundation.  For more
52    * information on the Apache Software Foundation, please see
53    * <http://www.apache.org/>.
54    */
55   
56   package org.apache.poi.util;
57   
58   import java.io.*;
59   
60   /**
61    * dump data in hexadecimal format; derived from a HexDump utility I
62    * wrote in June 2001.
63    *
64    * @author Marc Johnson
65    * @author Glen Stampoultzis  (glens at apache.org)
66    */
67   
68   public class HexDump
69   {
70   
71       // all static methods, so no need for a public constructor
72       private HexDump()
73       {
74       }
75   
76       /**
77        * dump an array of bytes to an OutputStream
78        *
79        * @param data the byte array to be dumped
80        * @param offset its offset, whatever that might mean
81        * @param stream the OutputStream to which the data is to be
82        *               written
83        * @param index initial index into the byte array
84        * @param length number of characters to output
85        *
86        * @exception IOException is thrown if anything goes wrong writing
87        *            the data to stream
88        * @exception ArrayIndexOutOfBoundsException if the index is
89        *            outside the data array's bounds
90        * @exception IllegalArgumentException if the output stream is
91        *            null
92        */
93       public synchronized static void dump(final byte [] data, final long offset,
94                               final OutputStream stream, final int index, final int length)
95               throws IOException, ArrayIndexOutOfBoundsException,
96                       IllegalArgumentException
97       {
98           if ((index < 0) || (index >= data.length))
99           {
100              throw new ArrayIndexOutOfBoundsException(
101                  "illegal index: " + index + " into array of length "
102                  + data.length);
103          }
104          if (stream == null)
105          {
106              throw new IllegalArgumentException("cannot write to nullstream");
107          }
108          long         display_offset = offset + index;
109          StringBuffer buffer         = new StringBuffer(74);
110  
111  
112          int data_length = Math.min(data.length,index+length);
113          for (int j = index; j < data_length; j += 16)
114          {
115              int chars_read = data_length - j;
116  
117              if (chars_read > 16)
118              {
119                  chars_read = 16;
120              }
121              buffer.append(
122                          dump(display_offset)
123                           ).append(' ');
124              for (int k = 0; k < 16; k++)
125              {
126                  if (k < chars_read)
127                  {
128                      buffer.append(dump(data[ k + j ]));
129                  }
130                  else
131                  {
132                      buffer.append("  ");
133                  }
134                  buffer.append(' ');
135              }
136              for (int k = 0; k < chars_read; k++)
137              {
138                  if ((data[ k + j ] >= ' ') && (data[ k + j ] < 127))
139                  {
140                      buffer.append(( char ) data[ k + j ]);
141                  }
142                  else
143                  {
144                      buffer.append('.');
145                  }
146              }
147              buffer.append(EOL);
148              stream.write(buffer.toString().getBytes());
149              stream.flush();
150              buffer.setLength(0);
151              display_offset += chars_read;
152          }
153  
154      }
155  
156      /**
157       * dump an array of bytes to an OutputStream
158       *
159       * @param data the byte array to be dumped
160       * @param offset its offset, whatever that might mean
161       * @param stream the OutputStream to which the data is to be
162       *               written
163       * @param index initial index into the byte array
164       *
165       * @exception IOException is thrown if anything goes wrong writing
166       *            the data to stream
167       * @exception ArrayIndexOutOfBoundsException if the index is
168       *            outside the data array's bounds
169       * @exception IllegalArgumentException if the output stream is
170       *            null
171       */
172  
173      public synchronized static void dump(final byte [] data, final long offset,
174                              final OutputStream stream, final int index)
175          throws IOException, ArrayIndexOutOfBoundsException,
176                  IllegalArgumentException
177      {
178          dump(data, offset, stream, index, data.length-index);
179      }
180  
181      /**
182       * dump an array of bytes to a String
183       *
184       * @param data the byte array to be dumped
185       * @param offset its offset, whatever that might mean
186       * @param index initial index into the byte array
187       *
188       * @exception ArrayIndexOutOfBoundsException if the index is
189       *            outside the data array's bounds
190       * @return output string
191       */
192      
193      public static String dump(final byte [] data, final long offset,
194                              final int index) {
195          StringBuffer buffer;
196          if ((index < 0) || (index >= data.length))
197          {
198              throw new ArrayIndexOutOfBoundsException(
199                  "illegal index: " + index + " into array of length "
200                  + data.length);
201          }
202          long         display_offset = offset + index;
203          buffer         = new StringBuffer(74);
204  
205          for (int j = index; j < data.length; j += 16)
206          {
207              int chars_read = data.length - j;
208  
209              if (chars_read > 16)
210              {
211                  chars_read = 16;
212              }
213              buffer.append(dump(display_offset)).append(' ');
214              for (int k = 0; k < 16; k++)
215              {
216                  if (k < chars_read)
217                  {
218                      buffer.append(dump(data[ k + j ]));
219                  }
220                  else
221                  {
222                      buffer.append("  ");
223                  }
224                  buffer.append(' ');
225              }
226              for (int k = 0; k < chars_read; k++)
227              {
228                  if ((data[ k + j ] >= ' ') && (data[ k + j ] < 127))
229                  {
230                      buffer.append(( char ) data[ k + j ]);
231                  }
232                  else
233                  {
234                      buffer.append('.');
235                  }
236              }
237              buffer.append(EOL);
238              display_offset += chars_read;
239          }                 
240          return buffer.toString();
241      }
242      
243  
244      public static final String        EOL         =
245          System.getProperty("line.separator");
246      private static final StringBuffer _lbuffer    = new StringBuffer(8);
247      private static final StringBuffer _cbuffer    = new StringBuffer(2);
248      private static final char         _hexcodes[] =
249      {
250          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
251          'E', 'F'
252      };
253      private static final int          _shifts[]   =
254      {
255          28, 24, 20, 16, 12, 8, 4, 0
256      };
257  
258      private static String dump(final long value)
259      {
260          _lbuffer.setLength(0);
261          for (int j = 0; j < 8; j++)
262          {
263              _lbuffer
264                  .append(_hexcodes[ (( int ) (value >> _shifts[ j ])) & 15 ]);
265          }
266          return _lbuffer.toString();
267      }
268  
269      private static String dump(final byte value)
270      {
271          _cbuffer.setLength(0);
272          for (int j = 0; j < 2; j++)
273          {
274              _cbuffer.append(_hexcodes[ (value >> _shifts[ j + 6 ]) & 15 ]);
275          }
276          return _cbuffer.toString();
277      }
278  
279      /**
280       * Converts the parameter to a hex value.
281       *
282       * @param value     The value to convert
283       * @return          A String representing the array of bytes
284       */
285      public static String toHex(final byte[] value)
286      {
287          StringBuffer retVal = new StringBuffer();
288          retVal.append('[');
289          for(int x = 0; x < value.length; x++)
290          {
291              retVal.append(toHex(value[x]));
292              retVal.append(", ");
293          }
294          retVal.append(']');
295          return retVal.toString();
296      }
297      /**
298       * Converts the parameter to a hex value.
299       *
300       * @param value     The value to convert
301       * @return          The result right padded with 0
302       */
303      public static String toHex(final short value)
304      {
305          return toHex(value, 4);
306      }
307  
308      /**
309       * Converts the parameter to a hex value.
310       *
311       * @param value     The value to convert
312       * @return          The result right padded with 0
313       */
314      public static String toHex(final byte value)
315      {
316          return toHex(value, 2);
317      }
318  
319      /**
320       * Converts the parameter to a hex value.
321       *
322       * @param value     The value to convert
323       * @return          The result right padded with 0
324       */
325      public static String toHex(final int value)
326      {
327          return toHex(value, 8);
328      }
329  
330  
331      private static String toHex(final long value, final int digits)
332      {
333          StringBuffer result = new StringBuffer(digits);
334          for (int j = 0; j < digits; j++)
335          {
336              result.append( _hexcodes[ (int) ((value >> _shifts[ j + (8 - digits) ]) & 15)]);
337          }
338          return result.toString();
339      }
340  }
341