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 package org.apache.commons.io; 018 019 import java.io.IOException; 020 import java.io.OutputStream; 021 022 /** 023 * Dumps data in hexadecimal format. 024 * <p> 025 * Provides a single function to take an array of bytes and display it 026 * in hexadecimal form. 027 * <p> 028 * Origin of code: POI. 029 * 030 * @version $Id: HexDump.java 1302748 2012-03-20 01:35:32Z ggregory $ 031 */ 032 public class HexDump { 033 034 /** 035 * Instances should NOT be constructed in standard programming. 036 */ 037 public HexDump() { 038 super(); 039 } 040 041 /** 042 * Dump an array of bytes to an OutputStream. The output is formatted 043 * for human inspection, with a hexadecimal offset followed by the 044 * hexadecimal values of the next 16 bytes of data and the printable ASCII 045 * characters (if any) that those bytes represent printed per each line 046 * of output. 047 * <p> 048 * The offset argument specifies the start offset of the data array 049 * within a larger entity like a file or an incoming stream. For example, 050 * if the data array contains the third kibibyte of a file, then the 051 * offset argument should be set to 2048. The offset value printed 052 * at the beginning of each line indicates where in that larger entity 053 * the first byte on that line is located. 054 * <p> 055 * All bytes between the given index (inclusive) and the end of the 056 * data array are dumped. 057 * 058 * @param data the byte array to be dumped 059 * @param offset offset of the byte array within a larger entity 060 * @param stream the OutputStream to which the data is to be 061 * written 062 * @param index initial index into the byte array 063 * 064 * @throws IOException is thrown if anything goes wrong writing 065 * the data to stream 066 * @throws ArrayIndexOutOfBoundsException if the index is 067 * outside the data array's bounds 068 * @throws IllegalArgumentException if the output stream is null 069 */ 070 071 public static void dump(byte[] data, long offset, 072 OutputStream stream, int index) 073 throws IOException, ArrayIndexOutOfBoundsException, 074 IllegalArgumentException { 075 076 if (index < 0 || index >= data.length) { 077 throw new ArrayIndexOutOfBoundsException( 078 "illegal index: " + index + " into array of length " 079 + data.length); 080 } 081 if (stream == null) { 082 throw new IllegalArgumentException("cannot write to nullstream"); 083 } 084 long display_offset = offset + index; 085 StringBuilder buffer = new StringBuilder(74); 086 087 for (int j = index; j < data.length; j += 16) { 088 int chars_read = data.length - j; 089 090 if (chars_read > 16) { 091 chars_read = 16; 092 } 093 dump(buffer, display_offset).append(' '); 094 for (int k = 0; k < 16; k++) { 095 if (k < chars_read) { 096 dump(buffer, data[k + j]); 097 } else { 098 buffer.append(" "); 099 } 100 buffer.append(' '); 101 } 102 for (int k = 0; k < chars_read; k++) { 103 if (data[k + j] >= ' ' && data[k + j] < 127) { 104 buffer.append((char) data[k + j]); 105 } else { 106 buffer.append('.'); 107 } 108 } 109 buffer.append(EOL); 110 stream.write(buffer.toString().getBytes()); 111 stream.flush(); 112 buffer.setLength(0); 113 display_offset += chars_read; 114 } 115 } 116 117 /** 118 * The line-separator (initializes to "line.separator" system property. 119 */ 120 public static final String EOL = 121 System.getProperty("line.separator"); 122 private static final char[] _hexcodes = 123 { 124 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 125 'A', 'B', 'C', 'D', 'E', 'F' 126 }; 127 private static final int[] _shifts = 128 { 129 28, 24, 20, 16, 12, 8, 4, 0 130 }; 131 132 /** 133 * Dump a long value into a StringBuilder. 134 * 135 * @param _lbuffer the StringBuilder to dump the value in 136 * @param value the long value to be dumped 137 * @return StringBuilder containing the dumped value. 138 */ 139 private static StringBuilder dump(StringBuilder _lbuffer, long value) { 140 for (int j = 0; j < 8; j++) { 141 _lbuffer 142 .append(_hexcodes[(int) (value >> _shifts[j]) & 15]); 143 } 144 return _lbuffer; 145 } 146 147 /** 148 * Dump a byte value into a StringBuilder. 149 * 150 * @param _cbuffer the StringBuilder to dump the value in 151 * @param value the byte value to be dumped 152 * @return StringBuilder containing the dumped value. 153 */ 154 private static StringBuilder dump(StringBuilder _cbuffer, byte value) { 155 for (int j = 0; j < 2; j++) { 156 _cbuffer.append(_hexcodes[value >> _shifts[j + 6] & 15]); 157 } 158 return _cbuffer; 159 } 160 161 }