blob: 8fbd5a41812fdff1495ffccdfbf91c791d831726 [file] [log] [blame]
// Copyright 2004 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry.util.io;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
/**
* A kind of super-formatter. It is sent a stream of binary data and
* formats it in a human-readable dump format which is forwarded to
* its output stream.
*
* <p>Currently, output is in hex though options to change that may
* be introduced.
*
* @author Howard Lewis Ship
* @version $Id$
*
**/
public class BinaryDumpOutputStream extends OutputStream
{
private PrintWriter out;
private boolean locked = false;
private boolean showOffset = true;
private int bytesPerLine = 16;
private int spacingInterval = 4;
private char substituteChar = '.';
private String offsetSeperator = ": ";
private int offset = 0;
private int lineCount = 0;
private int bytesSinceSpace = 0;
private char[] ascii = null;
private boolean showAscii = true;
private String asciiBegin = " |";
private String asciiEnd = "|";
private static final char[] HEX =
{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f' };
/**
* Creates a <code>PrintWriter</code> for <code>System.out</code>.
*
**/
public BinaryDumpOutputStream()
{
this(new PrintWriter(System.out, true));
}
public BinaryDumpOutputStream(PrintWriter out)
{
this.out = out;
}
public BinaryDumpOutputStream(Writer out)
{
this.out = new PrintWriter(out);
}
public void close() throws IOException
{
if (out != null)
{
if (lineCount > 0)
finishFinalLine();
out.close();
}
out = null;
}
private void finishFinalLine()
{
// Since we only finish the final line after at least one byte has
// been written to it, we don't need to worry about
// the offset.
while (lineCount < bytesPerLine)
{
// After every <n> bytes, emit a space.
if (spacingInterval > 0 && bytesSinceSpace == spacingInterval)
{
out.print(' ');
bytesSinceSpace = 0;
}
// Two spaces to substitute for the two hex digits.
out.print(" ");
if (showAscii)
ascii[lineCount] = ' ';
lineCount++;
bytesSinceSpace++;
}
if (showAscii)
{
out.print(asciiBegin);
out.print(ascii);
out.print(asciiEnd);
}
out.println();
}
/**
* Forwards the <code>flush()</code> to the <code>PrintWriter</code>.
*
**/
public void flush() throws IOException
{
out.flush();
}
public String getAsciiBegin()
{
return asciiBegin;
}
public String getAsciiEnd()
{
return asciiEnd;
}
public int getBytesPerLine()
{
return bytesPerLine;
}
public String getOffsetSeperator()
{
return offsetSeperator;
}
public boolean getShowAscii()
{
return showAscii;
}
public char getSubstituteChar()
{
return substituteChar;
}
public void setAsciiBegin(String value)
{
if (locked)
throw new IllegalStateException();
asciiBegin = value;
}
public void setAsciiEnd(String value)
{
if (locked)
throw new IllegalStateException();
asciiEnd = value;
}
public void setBytesPerLine(int value)
{
if (locked)
throw new IllegalStateException();
bytesPerLine = value;
ascii = null;
}
public void setOffsetSeperator(String value)
{
if (locked)
throw new IllegalStateException();
offsetSeperator = value;
}
public void setShowAscii(boolean value)
{
if (locked)
throw new IllegalStateException();
showAscii = value;
}
/**
* Sets the character used in the ASCII dump that substitutes for characters
* outside the range of 32..126.
*
**/
public void setSubstituteChar(char value)
{
if (locked)
throw new IllegalStateException();
substituteChar = value;
}
public void write(int b) throws IOException
{
char letter;
if (showAscii && ascii == null)
ascii = new char[bytesPerLine];
// Prevent further customization after output starts being written.
locked = true;
if (lineCount == bytesPerLine)
{
if (showAscii)
{
out.print(asciiBegin);
out.print(ascii);
out.print(asciiEnd);
}
out.println();
bytesSinceSpace = 0;
lineCount = 0;
offset += bytesPerLine;
}
if (lineCount == 0 && showOffset)
{
writeHex(offset, 4);
out.print(offsetSeperator);
}
// After every <n> bytes, emit a space.
if (spacingInterval > 0 && bytesSinceSpace == spacingInterval)
{
out.print(' ');
bytesSinceSpace = 0;
}
writeHex(b, 2);
if (showAscii)
{
if (b < 32 | b > 127)
letter = substituteChar;
else
letter = (char) b;
ascii[lineCount] = letter;
}
lineCount++;
bytesSinceSpace++;
}
private void writeHex(int value, int digits)
{
int i;
int nybble;
for (i = 0; i < digits; i++)
{
nybble = (value >> 4 * (digits - i - 1)) & 0x0f;
out.print(HEX[nybble]);
}
}
}