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