Hex Viewer
----------------- HexView.java -----------------
import java.io.*;
import java.util.*;
import java.nio.*;
import java.nio.charset.*;
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.*;
import javafx.scene.text.*;
import javafx.collections.*;
import javafx.beans.property.*;
import javafx.util.*;
public class HexView extends Application {
RandomAccessFile raf = null;
int size = 0;
@Override
public void start(Stage stage) {
File file;
List<String> p = getParameters().getRaw();
if (!p.isEmpty()) {
file = new File(p.get(0));
if (!file.isFile()) throw new RuntimeException(file.getName() + " file not found");
} else {
file = new File("demo.bin");
if (!file.exists()) createDemo(file);
}
try {
raf = new RandomAccessFile(file, "rw");
if (raf.length() > 0) size = (int)((raf.length() - 1) / 16 + 1);
} catch (Exception e) { }
iniCharTable(Charset.defaultCharset());
BorderPane layout = new BorderPane();
stage.setScene(new Scene(layout, 700, 400));
TableView<Integer> tableView = new TableView<>();
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableView.setItems(new ObservableListBase<Integer>() {
Integer value = Integer.valueOf(-1);
@Override
public int size() {
return size;
}
@Override
public Integer get(int index) {
if (index < 0 || index >= size()) throw new IndexOutOfBoundsException();
if (index != value.intValue()) {
value = Integer.valueOf(index);
}
return value;
}
});
TableColumn<Integer, String> column = new TableColumn<>(file.getName());
column.setCellValueFactory(cellData -> {
return new ReadOnlyObjectWrapper<String>(createItem(cellData.getValue()));
});
Font font = Font.font("Monospaced");
Callback<TableColumn<Integer, String>,TableCell<Integer, String>> columnCellFactory = column.getCellFactory();
column.setCellFactory(col -> {
TableCell<Integer, String> cell = columnCellFactory.call(col);
cell.setFont(font);
return cell;
});
tableView.getColumns().add(column);
tableView.getSelectionModel().selectFirst();
tableView.sortPolicyProperty().set(t -> false);
layout.setCenter(tableView);
stage.setOnCloseRequest(event -> {
try { raf.close(); } catch (Exception e) { }
});
stage.show();
}
StringBuilder sb = new StringBuilder();
char charTable[] = new char[224];
byte[] bytes = new byte[16];
char emp = '\u0020', priv = '\uE000', pnt = '\u00B7';
char hexDigit[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
char charControl[] = {
'\u0020', '\u263A', '\u263B', '\u2665', '\u2666', '\u2663', '\u2660', '\u2022',
'\u25D8', '\u25CB', '\u25D9', '\u2642', '\u2640', '\u266A', '\u266B', '\u263C',
'\u25BA', '\u25C4', '\u2195', '\u203C', '\u00B6', '\u00A7', '\u25AC', '\u21A8',
'\u2191', '\u2193', '\u2192', '\u2190', '\u221F', '\u2194', '\u25B2', '\u25BC'
};
boolean iniCharTable(Charset charset) {
CharsetDecoder decoder = charset.newDecoder();
boolean sbcs = decoder.maxCharsPerByte() == 1 && decoder.averageCharsPerByte() == 1;
if (!sbcs) decoder = Charset.forName("Cp1252").newDecoder();
ByteBuffer bb = ByteBuffer.allocate(1);
CharBuffer cb = CharBuffer.allocate(1);
for (int i = 0; i < 224; i++) {
try {
bb.put(0, (byte)(i + 0x20));
bb.position(0);
cb.position(0);
decoder.reset();
if (decoder.decode(bb, cb, true).isError()) charTable[i] = priv;
else charTable[i] = cb.get(0);
} catch (Exception e) { charTable[i] = priv; }
}
return sbcs;
}
String createItem(int value) {
sb.setLength(0);
int length = 0;
try {
raf.seek(value * 16);
length = raf.read(bytes);
} catch (Exception e) { return null; }
for (int i = 28; i >= 0; i-=4) {
sb.append(hexDigit[0x0F & value >>> i]);
}
sb.append('0').append(':').append(emp).append(emp);
for (int i = 0; i < 16; i++) {
if (i < length) {
sb.append(hexDigit[0x0F & bytes[i] >> 4]);
sb.append(hexDigit[0x0F & bytes[i]]);
} else { sb.append(emp).append(emp); }
sb.append(emp);
if (i == 7) sb.append(emp);
}
sb.append(emp);
for (int i = 0; i < 16; i++) {
if (i >= length) { sb.append(emp); continue; }
int code = 0xFF & (int)bytes[i];
if (code >= 0x00 && code < 0x20) { sb.append(charControl[code]); continue; }
char uc = charTable[code - 0x20];
if (uc >= '\u0000' && uc < '\u0020') sb.append(charControl[(int)uc]);
else if (uc == '\u0085' || uc == '\u2028' || uc == '\u2029') sb.append(charControl[0x0A]);
else if (uc == priv) sb.append(pnt);
else sb.append(uc);
}
return sb.toString();
}
void createDemo(File file) {
try (RandomAccessFile rafd = new RandomAccessFile(file, "rw")) {
rafd.setLength(0L);
for (int i = 0; i < 256; i++) rafd.write((byte)i);
rafd.write("End".getBytes());
} catch (Exception e) { }
}
}