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        *
85        * @exception IOException is thrown if anything goes wrong writing
86        *            the data to stream
87        * @exception ArrayIndexOutOfBoundsException if the index is
88        *            outside the data array's bounds
89        * @exception IllegalArgumentException if the output stream is
90        *            null
91        */
92   
93       public synchronized static void dump(final byte [] data, final long offset,
94                               final OutputStream stream, final int index)
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          for (int j = index; j < data.length; j += 16)
112          {
113              int chars_read = data.length - j;
114  
115              if (chars_read > 16)
116              {
117                  chars_read = 16;
118              }
119              buffer.append(dump(display_offset)).append(' ');
120              for (int k = 0; k < 16; k++)
121              {
122                  if (k < chars_read)
123                  {
124                      buffer.append(dump(data[ k + j ]));
125                  }
126                  else
127                  {
128                      buffer.append("  ");
129                  }
130                  buffer.append(' ');
131              }
132              for (int k = 0; k < chars_read; k++)
133              {
134                  if ((data[ k + j ] >= ' ') && (data[ k + j ] < 127))
135                  {
136                      buffer.append(( char ) data[ k + j ]);
137                  }
138                  else
139                  {
140                      buffer.append('.');
141                  }
142              }
143              buffer.append(EOL);
144              stream.write(buffer.toString().getBytes());
145              stream.flush();
146              buffer.setLength(0);
147              display_offset += chars_read;
148          }
149      }
150  
151      /**
152       * dump an array of bytes to a String
153       *
154       * @param data the byte array to be dumped
155       * @param offset its offset, whatever that might mean
156       * @param index initial index into the byte array
157       *
158       * @exception IOException is thrown if anything goes wrong writing
159       *            the data to stream
160       * @exception ArrayIndexOutOfBoundsException if the index is
161       *            outside the data array's bounds
162       * @return output string
163       */
164      
165      public static String dump(final byte [] data, final long offset,
166                              final int index) {
167          StringBuffer buffer;
168          if ((index < 0) || (index >= data.length))
169          {
170              throw new ArrayIndexOutOfBoundsException(
171                  "illegal index: " + index + " into array of length "
172                  + data.length);
173          }
174          long         display_offset = offset + index;
175          buffer         = new StringBuffer(74);
176  
177          for (int j = index; j < data.length; j += 16)
178          {
179              int chars_read = data.length - j;
180  
181              if (chars_read > 16)
182              {
183                  chars_read = 16;
184              }
185              buffer.append(dump(display_offset)).append(' ');
186              for (int k = 0; k < 16; k++)
187              {
188                  if (k < chars_read)
189                  {
190                      buffer.append(dump(data[ k + j ]));
191                  }
192                  else
193                  {
194                      buffer.append("  ");
195                  }
196                  buffer.append(' ');
197              }
198              for (int k = 0; k < chars_read; k++)
199              {
200                  if ((data[ k + j ] >= ' ') && (data[ k + j ] < 127))
201                  {
202                      buffer.append(( char ) data[ k + j ]);
203                  }
204                  else
205                  {
206                      buffer.append('.');
207                  }
208              }
209              buffer.append(EOL);
210              display_offset += chars_read;
211          }                 
212          return buffer.toString();
213      }
214      
215  
216      public static final String        EOL         =
217          System.getProperty("line.separator");
218      private static final StringBuffer _lbuffer    = new StringBuffer(8);
219      private static final StringBuffer _cbuffer    = new StringBuffer(2);
220      private static final char         _hexcodes[] =
221      {
222          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
223          'E', 'F'
224      };
225      private static final int          _shifts[]   =
226      {
227          28, 24, 20, 16, 12, 8, 4, 0
228      };
229  
230      private static StringBuffer dump(final long value)
231      {
232          _lbuffer.setLength(0);
233          for (int j = 0; j < 8; j++)
234          {
235              _lbuffer
236                  .append(_hexcodes[ (( int ) (value >> _shifts[ j ])) & 15 ]);
237          }
238          return _lbuffer;
239      }
240  
241      private static StringBuffer dump(final byte value)
242      {
243          _cbuffer.setLength(0);
244          for (int j = 0; j < 2; j++)
245          {
246              _cbuffer.append(_hexcodes[ (value >> _shifts[ j + 6 ]) & 15 ]);
247          }
248          return _cbuffer;
249      }
250  
251      /**
252       * Converts the parameter to a hex value.
253       *
254       * @param value     The value to convert
255       * @return          A String representing the array of bytes
256       */
257      public static String toHex(final byte[] value)
258      {
259          StringBuffer retVal = new StringBuffer();
260          retVal.append('[');
261          for(int x = 0; x < value.length; x++)
262          {
263              retVal.append(toHex(value[x]));
264              retVal.append(", ");
265          }
266          retVal.append(']');
267          return retVal.toString();
268      }
269      /**
270       * Converts the parameter to a hex value.
271       *
272       * @param value     The value to convert
273       * @return          The result right padded with 0
274       */
275      public static String toHex(final short value)
276      {
277          return toHex(value, 4);
278      }
279  
280      /**
281       * Converts the parameter to a hex value.
282       *
283       * @param value     The value to convert
284       * @return          The result right padded with 0
285       */
286      public static String toHex(final byte value)
287      {
288          return toHex(value, 2);
289      }
290  
291      /**
292       * Converts the parameter to a hex value.
293       *
294       * @param value     The value to convert
295       * @return          The result right padded with 0
296       */
297      public static String toHex(final int value)
298      {
299          return toHex(value, 8);
300      }
301  
302  
303      private static String toHex(final long value, final int digits)
304      {
305          StringBuffer result = new StringBuffer(digits);
306          for (int j = 0; j < digits; j++)
307          {
308              result.append( _hexcodes[ (int) ((value >> _shifts[ j + (8 - digits) ]) & 15)]);
309          }
310          return result.toString();
311      }
312  }
313