Rev 311 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2007 Steve Ratcliffe
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* Author: Steve Ratcliffe
* Create date: Dec 16, 2007
*/
package test.display;
import uk.me.parabola.imgfmt.app.ImgFileReader;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
/**
* Displays data in a manner similar to imgdecode written by John Mechalas.
*
* So we have an address on the left, un-decoded bytes in the middle and
* the decoded text and explanation on the right.
*
* @author Steve Ratcliffe
*/
public class Displayer
{
private static final String SEPARATOR =
"---------------------------------"
+
"---------------------------------------------------------------"
+
"---------------------------------------------------------------"
;
private static final int TABLE_WIDTH =
80;
private String title
;
private final List<DisplayItem
> items =
new ArrayList<DisplayItem
>();
private final ImgFileReader reader
;
// References relative to the section start are much more useful for
// some purposes.
private long sectStart
;
public Displayer
(ImgFileReader reader
) {
this.
reader = reader
;
}
/**
* Prints this displayer, and causes all the contained display items to
* be printed out.
* @param writer The stream to write to.
*/
public void print
(PrintStream writer
) {
if (writer ==
null) {
items.
clear();
return;
}
printTitle
(writer
);
for (DisplayItem item : items
) {
item.
print(writer
);
}
items.
clear();
writer.
flush();
}
private void printTitle
(PrintStream writer
) {
if (title ==
null)
return;
int leadin =
9;
writer.
printf("%s ", SEPARATOR.
substring(0, leadin
));
writer.
print(title
);
writer.
printf(" %s", SEPARATOR.
substring(0, TABLE_WIDTH - leadin - title.
length() -
2));
writer.
println();
}
public void setTitle
(String title
) {
this.
title = title
;
}
/**
* Create a display item for the current position. You can add data and
* lines of text to it. If you can its easier to use the convenience
* routines below.
*
* This must be called *before* getting any data from the reader as it
* records the file position.
*
* @return A display item.
*/
public DisplayItem item
() {
DisplayItem item =
new DisplayItem
();
item.
setStartPos(reader.
position());
item.
setSectStart(sectStart
);
items.
add(item
);
return item
;
}
/**
* Draw a line across the display.
*/
public void line
() {
item
().
addText("------");
}
/**
* Make a gap in the display, nothing will be printed apart from the
* separators.
*/
public void gap
() {
item
().
addText(" ");
}
public byte byteValue
(String text
) {
DisplayItem item = byteItem
();
int val = item.
getValue();
if (text
!=
null)
item.
addText(text, val
& 0xff
);
return (byte) (val
& 0xff
);
}
public DisplayItem byteItem
() {
DisplayItem item = item
();
item.
setBytes(reader.
get());
return item
;
}
public char charValue
(String text
) {
DisplayItem item = charItem
();
int val = item.
getValue();
if (text
!=
null)
item.
addText(text,
(val
& 0xffff
));
return (char) val
;
}
public DisplayItem charItem
() {
DisplayItem item = item
();
item.
setBytes(reader.
getChar());
return item
;
}
public short shortValue
(String text
) {
DisplayItem item = item
();
item.
setBytes(reader.
getChar());
short val =
(short) item.
getValue();
if (text
!=
null)
item.
addText(text,
(short) val
);
return val
;
}
public int intValue
(String text
) {
DisplayItem item = intItem
();
int val = item.
getValue();
if (text
!=
null)
item.
addText(text, val
);
return val
;
}
public DisplayItem intItem
() {
DisplayItem item = item
();
item.
setBytes(reader.
getInt());
return item
;
}
public DisplayItem intItem
(int n
) {
DisplayItem item = item
();
switch (n
) {
case 1:
item.
setBytes(reader.
get());
break;
case 2:
item.
setBytes(reader.
getChar());
break;
case 3:
item.
setBytes3(reader.
get3());
break;
case 4:
item.
setBytes(reader.
getInt());
break;
}
return item
;
}
public int intValue
(int n,
String text
) {
switch (n
) {
case 1:
return byteValue
(text
) & 0xff
;
case 2:
return charValue
(text
);
case 3:
return int3Value
(text
);
case 4:
return intValue
(text
);
}
return 0;
}
/**
* Display an unsigned 3 byte quantity.
*/
public int int3Value
(String text
) {
DisplayItem item = int3Item
();
int val = item.
getValue();
if (text
!=
null)
item.
addText(text,
(val
& 0xffffff
));
return val
;
}
public DisplayItem int3Item
() {
DisplayItem item = item
();
item.
setBytes3(reader.
get3());
return item
;
}
public int int3sValue
(String text
) {
DisplayItem item = int3Item
();
int val = item.
getValue();
if ((val
& 0x800000
) !=
0)
val |= 0xff000000
;
if (text
!=
null)
item.
addText(text, val
);
return val
;
}
public DisplayItem rawItem
(int n
) {
DisplayItem item = item
();
byte[] buf = reader.
get(n
);
item.
setBytes(buf
);
return item
;
}
public byte[] rawValue
(int n,
String text
) {
if (n
<=
0)
return null;
DisplayItem item = item
();
byte[] buf = reader.
get(n
);
item.
setBytes(buf
);
if (text
!=
null)
item.
addText(text +
" (len: %d, %#x)", n, n
);
return buf
;
}
public void stringValue
(int n,
String text
) {
DisplayItem item = item
();
byte[] b = item.
setBytes(reader.
get(n
));
String val =
new String(b
);
if (text
!=
null)
item.
addText(text, val
);
}
/**
* Display a zero terminated string.
* @param text Description of the value.
* @return The value as a string, remember that the nul byte is not included
* so that the string will be one less in length than in the file.
*/
public String zstringValue
(String text
) {
return zstringValue
(text,
"latin1");
}
public String zstringValue
(String text,
String charsetName
) {
DisplayItem item = item
();
ByteArrayOutputStream os =
new ByteArrayOutputStream();
byte b
;
while ((b = reader.
get()) !=
'\0')
os.
write(b
);
String val =
null;
try {
val = os.
toString(charsetName
);
} catch (UnsupportedEncodingException e
) {
val = os.
toString();
}
os.
write('\0');
item.
setBytes(os.
toByteArray());
if (text
!=
null)
item.
addText(text, val
);
return val
;
}
public void rawValue
(int n
) {
if (n
<=
0) {
if (n
< 0)
item
().
addText("overshoot %d", n
);
return;
}
item
().
addText("Unknown %d bytes:", n
);
DisplayItem item = item
();
byte[] bytes = item.
setBytes(reader.
get(n
));
StringBuffer sb =
new StringBuffer();
for (int count =
0; count
< bytes.
length; count++
) {
char c =
(char) (bytes
[count
] & 0xff
);
sb.
append(/*Character.isLetterOrDigit(c)*/ c
>= 0x20
? c :
'.');
if ((count
& 0x7
) ==
7) {
item.
addText(sb.
toString());
sb =
new StringBuffer();
}
}
if (sb.
length() > 0)
item.
addText(sb.
toString());
}
public void setSectStart
(long sectStart
) {
this.
sectStart = sectStart
;
}
}