com.packenius.dumpapi.DumpBlock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.packenius.dumpapi Show documentation
Show all versions of com.packenius.dumpapi Show documentation
A small API for creating byte stream dumps.
package com.packenius.dumpapi;
import java.util.Arrays;
import java.util.List;
import com.packenius.hexr.HexR;
/**
* Part of a byte array (of a data stream, of a file, ...).
* @author Christian Packenius, 2016.
*/
public abstract class DumpBlock implements Comparable {
/**
* Carriage Return / Line Feed.
*/
private static final String CRLF = System.getProperty("line.separator");
public final DumpReader reader;
/**
* Start address (inclusive) of this block.
*/
private final int startAddress;
/**
* End address (exclusive) of this block.
*/
private int endAddress = -1;
/**
* Cross pointer leads to another dump block anywhere within the dumped content.
*/
private CrossPointer crossPointer;
/**
* Constructor.
* @param reader Dump reader.
*/
public DumpBlock(DumpReader reader) {
this.reader = reader;
startAddress = reader.getCurrentIndex();
reader.startDumpBlock(this);
}
/**
* Set the (exclusive) end address of this dump block. This block will be
* finished within the reader after setting end address.
* @param reader The current address of this reader is used as end address.
*/
public void setEndAddress(DumpReader reader) {
int endAddress = reader.getCurrentIndex();
setEndAddress(endAddress);
reader.endDumpBlock(this);
}
/**
* Set end address of this block.
* @param endAddress End address to set (exclusive).
*/
public void setEndAddress(int endAddress) {
if (endAddress < 0) {
throw new IllegalArgumentException("End address negative: " + endAddress);
}
if (endAddress < getStartAddress()) {
throw new IllegalArgumentException(
"End address before start address: start=" + getStartAddress() + ", end=" + endAddress);
}
this.endAddress = endAddress;
}
/**
* Returns the title of this dump block. This can be a static or dynamic
* generated string.
*/
@Override
public abstract String toString();
/**
* Returns a description of the dump block content. The returned text will be
* word wrapped if too long for a single line.
* Please overwrite this method.
*/
public String getDescription() {
return null;
}
public int getStartAddress() {
return startAddress;
}
public int getEndAddress() {
if (endAddress < 0) {
throw new RuntimeException("End address has not been set!");
}
return endAddress;
}
@Override
public int compareTo(DumpBlock block2) {
return startAddress - block2.startAddress;
}
public int getByteSize() {
return getEndAddress() - startAddress;
}
public void setCrossPointer(CrossPointer crossPointer) {
this.crossPointer = crossPointer;
}
public CrossPointer getCrossPointer() {
return crossPointer;
}
public boolean hasCrossPointer() {
return crossPointer != null;
}
/**
* Creates a hex dump of this block (and all child blocks) into the
* StringBuilder object.
* @return Returns true if the last written line has been written as a
* leaf (so: with hex codes).
*/
public boolean dump(StringBuilder sb, String prefix, boolean lastLineWasLeaf) {
String prefix2;
if (prefix == null) {
prefix = "";
prefix2 = "";
} else {
if (!lastLineWasLeaf) {
sb.append(CRLF);
}
prefix2 = prefix + " ";
}
// Node without child nodes (:: a leaf)?
List subBlocks = reader.getSubBlocks(this);
if (subBlocks == null || subBlocks.isEmpty() || this instanceof TechnicalDumpBlock) {
dumpLeaf(sb, prefix);
return true;
}
// No, this is also a parent node.
else {
if (lastLineWasLeaf) {
sb.append(CRLF);
}
dumpWithHeadline(sb, prefix2, subBlocks);
return false;
}
}
private void dumpLeaf(StringBuilder sb, String prefix) {
HexR hexR = new HexR();
hexR.setFirstMemoryAddress(getStartAddress());
hexR.setHexCodesPerLine(18);
hexR.setResultType(String[].class);
String[] hexCodes = (String[]) hexR.dump(reader.getContent(), getStartAddress(), getEndAddress());
String text = toString();
for (String hexLine : hexCodes) {
sb.append(prefix).append(hexLine).append(" ").append(text).append(CRLF);
text = "";
}
}
private void dumpWithHeadline(StringBuilder sb, String prefix, List subBlocks) {
String text = toString();
char[] ba = new char[text.length()];
Arrays.fill(ba, '-');
sb.append(prefix).append(text).append(CRLF).append(prefix).append(ba).append(CRLF);
boolean lastLineWasLeaf = false;
for (DumpBlock block : subBlocks) {
lastLineWasLeaf = block.dump(sb, prefix, lastLineWasLeaf);
}
}
}