001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.util;
019:
020: import java.io.*;
021: import java.text.DecimalFormat;
022:
023: /**
024: * dump data in hexadecimal format; derived from a HexDump utility I
025: * wrote in June 2001.
026: *
027: * @author Marc Johnson
028: * @author Glen Stampoultzis (glens at apache.org)
029: */
030:
031: public class HexDump {
032: public static final String EOL = System
033: .getProperty("line.separator");
034: // private static final StringBuffer _lbuffer = new StringBuffer(8);
035: // private static final StringBuffer _cbuffer = new StringBuffer(2);
036: private static final char _hexcodes[] = { '0', '1', '2', '3', '4',
037: '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
038: private static final int _shifts[] = { 60, 56, 52, 48, 44, 40, 36,
039: 32, 28, 24, 20, 16, 12, 8, 4, 0 };
040:
041: // all static methods, so no need for a public constructor
042: private HexDump() {
043: }
044:
045: /**
046: * dump an array of bytes to an OutputStream
047: *
048: * @param data the byte array to be dumped
049: * @param offset its offset, whatever that might mean
050: * @param stream the OutputStream to which the data is to be
051: * written
052: * @param index initial index into the byte array
053: * @param length number of characters to output
054: *
055: * @exception IOException is thrown if anything goes wrong writing
056: * the data to stream
057: * @exception ArrayIndexOutOfBoundsException if the index is
058: * outside the data array's bounds
059: * @exception IllegalArgumentException if the output stream is
060: * null
061: */
062: public synchronized static void dump(final byte[] data,
063: final long offset, final OutputStream stream,
064: final int index, final int length) throws IOException,
065: ArrayIndexOutOfBoundsException, IllegalArgumentException {
066: if (data.length == 0) {
067: stream.write(("No Data" + System
068: .getProperty("line.separator")).getBytes());
069: stream.flush();
070: return;
071: }
072: if ((index < 0) || (index >= data.length)) {
073: throw new ArrayIndexOutOfBoundsException("illegal index: "
074: + index + " into array of length " + data.length);
075: }
076: if (stream == null) {
077: throw new IllegalArgumentException(
078: "cannot write to nullstream");
079: }
080:
081: long display_offset = offset + index;
082: StringBuffer buffer = new StringBuffer(74);
083:
084: int data_length = Math.min(data.length, index + length);
085: for (int j = index; j < data_length; j += 16) {
086: int chars_read = data_length - j;
087:
088: if (chars_read > 16) {
089: chars_read = 16;
090: }
091: buffer.append(dump(display_offset)).append(' ');
092: for (int k = 0; k < 16; k++) {
093: if (k < chars_read) {
094: buffer.append(dump(data[k + j]));
095: } else {
096: buffer.append(" ");
097: }
098: buffer.append(' ');
099: }
100: for (int k = 0; k < chars_read; k++) {
101: if ((data[k + j] >= ' ') && (data[k + j] < 127)) {
102: buffer.append((char) data[k + j]);
103: } else {
104: buffer.append('.');
105: }
106: }
107: buffer.append(EOL);
108: stream.write(buffer.toString().getBytes());
109: stream.flush();
110: buffer.setLength(0);
111: display_offset += chars_read;
112: }
113:
114: }
115:
116: /**
117: * dump an array of bytes to an OutputStream
118: *
119: * @param data the byte array to be dumped
120: * @param offset its offset, whatever that might mean
121: * @param stream the OutputStream to which the data is to be
122: * written
123: * @param index initial index into the byte array
124: *
125: * @exception IOException is thrown if anything goes wrong writing
126: * the data to stream
127: * @exception ArrayIndexOutOfBoundsException if the index is
128: * outside the data array's bounds
129: * @exception IllegalArgumentException if the output stream is
130: * null
131: */
132:
133: public synchronized static void dump(final byte[] data,
134: final long offset, final OutputStream stream,
135: final int index) throws IOException,
136: ArrayIndexOutOfBoundsException, IllegalArgumentException {
137: dump(data, offset, stream, index, data.length - index);
138: }
139:
140: /**
141: * dump an array of bytes to a String
142: *
143: * @param data the byte array to be dumped
144: * @param offset its offset, whatever that might mean
145: * @param index initial index into the byte array
146: *
147: * @exception ArrayIndexOutOfBoundsException if the index is
148: * outside the data array's bounds
149: * @return output string
150: */
151:
152: public static String dump(final byte[] data, final long offset,
153: final int index) {
154: StringBuffer buffer;
155: if ((index < 0) || (index >= data.length)) {
156: throw new ArrayIndexOutOfBoundsException("illegal index: "
157: + index + " into array of length " + data.length);
158: }
159: long display_offset = offset + index;
160: buffer = new StringBuffer(74);
161:
162: for (int j = index; j < data.length; j += 16) {
163: int chars_read = data.length - j;
164:
165: if (chars_read > 16) {
166: chars_read = 16;
167: }
168: buffer.append(dump(display_offset)).append(' ');
169: for (int k = 0; k < 16; k++) {
170: if (k < chars_read) {
171: buffer.append(dump(data[k + j]));
172: } else {
173: buffer.append(" ");
174: }
175: buffer.append(' ');
176: }
177: for (int k = 0; k < chars_read; k++) {
178: if ((data[k + j] >= ' ') && (data[k + j] < 127)) {
179: buffer.append((char) data[k + j]);
180: } else {
181: buffer.append('.');
182: }
183: }
184: buffer.append(EOL);
185: display_offset += chars_read;
186: }
187: return buffer.toString();
188: }
189:
190: private static String dump(final long value) {
191: StringBuffer buf = new StringBuffer();
192: buf.setLength(0);
193: for (int j = 0; j < 8; j++) {
194: buf.append(_hexcodes[((int) (value >> _shifts[j
195: + _shifts.length - 8])) & 15]);
196: }
197: return buf.toString();
198: }
199:
200: private static String dump(final byte value) {
201: StringBuffer buf = new StringBuffer();
202: buf.setLength(0);
203: for (int j = 0; j < 2; j++) {
204: buf.append(_hexcodes[(value >> _shifts[j + 6]) & 15]);
205: }
206: return buf.toString();
207: }
208:
209: /**
210: * Converts the parameter to a hex value.
211: *
212: * @param value The value to convert
213: * @return A String representing the array of bytes
214: */
215: public static String toHex(final byte[] value) {
216: StringBuffer retVal = new StringBuffer();
217: retVal.append('[');
218: for (int x = 0; x < value.length; x++) {
219: retVal.append(toHex(value[x]));
220: retVal.append(", ");
221: }
222: retVal.append(']');
223: return retVal.toString();
224: }
225:
226: /**
227: * Converts the parameter to a hex value.
228: *
229: * @param value The value to convert
230: * @return A String representing the array of shorts
231: */
232: public static String toHex(final short[] value) {
233: StringBuffer retVal = new StringBuffer();
234: retVal.append('[');
235: for (int x = 0; x < value.length; x++) {
236: retVal.append(toHex(value[x]));
237: retVal.append(", ");
238: }
239: retVal.append(']');
240: return retVal.toString();
241: }
242:
243: /**
244: * <p>Converts the parameter to a hex value breaking the results into
245: * lines.</p>
246: *
247: * @param value The value to convert
248: * @param bytesPerLine The maximum number of bytes per line. The next byte
249: * will be written to a new line
250: * @return A String representing the array of bytes
251: */
252: public static String toHex(final byte[] value,
253: final int bytesPerLine) {
254: final int digits = (int) Math.round(Math.log(value.length)
255: / Math.log(10) + 0.5);
256: final StringBuffer formatString = new StringBuffer();
257: for (int i = 0; i < digits; i++)
258: formatString.append('0');
259: formatString.append(": ");
260: final DecimalFormat format = new DecimalFormat(formatString
261: .toString());
262: StringBuffer retVal = new StringBuffer();
263: retVal.append(format.format(0));
264: int i = -1;
265: for (int x = 0; x < value.length; x++) {
266: if (++i == bytesPerLine) {
267: retVal.append('\n');
268: retVal.append(format.format(x));
269: i = 0;
270: }
271: retVal.append(toHex(value[x]));
272: retVal.append(", ");
273: }
274: return retVal.toString();
275: }
276:
277: /**
278: * Converts the parameter to a hex value.
279: *
280: * @param value The value to convert
281: * @return The result right padded with 0
282: */
283: public static String toHex(final short value) {
284: return toHex(value, 4);
285: }
286:
287: /**
288: * Converts the parameter to a hex value.
289: *
290: * @param value The value to convert
291: * @return The result right padded with 0
292: */
293: public static String toHex(final byte value) {
294: return toHex(value, 2);
295: }
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 int value) {
304: return toHex(value, 8);
305: }
306:
307: /**
308: * Converts the parameter to a hex value.
309: *
310: * @param value The value to convert
311: * @return The result right padded with 0
312: */
313: public static String toHex(final long value) {
314: return toHex(value, 16);
315: }
316:
317: private static String toHex(final long value, final int digits) {
318: StringBuffer result = new StringBuffer(digits);
319: for (int j = 0; j < digits; j++) {
320: result.append(_hexcodes[(int) ((value >> _shifts[j
321: + (16 - digits)]) & 15)]);
322: }
323: return result.toString();
324: }
325:
326: /**
327: * Dumps <code>bytesToDump</code> bytes to an output stream.
328: *
329: * @param in The stream to read from
330: * @param out The output stream
331: * @param start The index to use as the starting position for the left hand side label
332: * @param bytesToDump The number of bytes to output. Use -1 to read until the end of file.
333: */
334: public static void dump(InputStream in, PrintStream out, int start,
335: int bytesToDump) throws IOException {
336: ByteArrayOutputStream buf = new ByteArrayOutputStream();
337: if (bytesToDump == -1) {
338: int c = in.read();
339: while (c != -1) {
340: buf.write(c);
341: c = in.read();
342: }
343: } else {
344: int bytesRemaining = bytesToDump;
345: while (bytesRemaining-- > 0) {
346: int c = in.read();
347: if (c == -1)
348: break;
349: else
350: buf.write(c);
351: }
352: }
353:
354: byte[] data = buf.toByteArray();
355: dump(data, 0, out, start, data.length);
356: }
357:
358: public static void main(String[] args) throws Exception {
359: File file = new File(args[0]);
360: InputStream in = new BufferedInputStream(new FileInputStream(
361: file));
362: byte[] b = new byte[(int) file.length()];
363: in.read(b);
364: System.out.println(HexDump.dump(b, 0, 0));
365: in.close();
366: }
367: }
|