GT-3294 Added support for DB FixedField with improved indexing.

This commit is contained in:
ghidra1 2020-02-24 18:02:01 -05:00
parent 14d4c87ef4
commit fcb3151f94
224 changed files with 9574 additions and 7913 deletions

View file

@ -23,7 +23,6 @@ import java.io.IOException;
import java.util.*;
import javax.swing.*;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import db.buffers.LocalBufferFile;
@ -33,6 +32,8 @@ import docking.widgets.combobox.GComboBox;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel;
import ghidra.app.plugin.debug.dbtable.DbLargeTableModel;
import ghidra.app.plugin.debug.dbtable.DbSmallTableModel;
import ghidra.framework.Application;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.util.Msg;
@ -292,525 +293,3 @@ public class DbViewer extends JFrame {
}
}
class ColumnAdapter {
static final int BYTE = 0;
static final int BOOLEAN = 1;
static final int SHORT = 2;
static final int INT = 3;
static final int LONG = 4;
static final int STRING = 5;
static final int BINARY = 6;
int type;
Class<?> valueClass;
ColumnAdapter(Class<?> c) {
if (c == ByteField.class) {
type = BYTE;
valueClass = Byte.class;
}
else if (c == BooleanField.class) {
type = BOOLEAN;
valueClass = Boolean.class;
}
else if (c == ShortField.class) {
type = SHORT;
valueClass = Short.class;
}
else if (c == IntField.class) {
type = INT;
valueClass = Integer.class;
}
else if (c == LongField.class) {
type = LONG;
//valueClass = Long.class;
valueClass = String.class;
}
else if (c == StringField.class) {
type = STRING;
valueClass = String.class;
}
else if (c == BinaryField.class) {
type = BINARY;
valueClass = String.class;
}
}
Class<?> getValueClass() {
return valueClass;
}
Object getKeyValue(Record rec) {
switch (type) {
case BYTE:
return new Byte(((ByteField) rec.getKeyField()).getByteValue());
case BOOLEAN:
return new Boolean(((BooleanField) rec.getKeyField()).getBooleanValue());
case SHORT:
return new Short(((ShortField) rec.getKeyField()).getShortValue());
case INT:
return new Integer(((IntField) rec.getKeyField()).getIntValue());
case LONG:
return "0x" + Long.toHexString(rec.getKey());
//return new Long(rec.getKey());
case STRING:
return ((StringField) rec.getKeyField()).getString();
case BINARY:
byte[] bytes = ((BinaryField) rec.getKeyField()).getBinaryData();
StringBuffer buf = new StringBuffer(" byte[" + bytes.length + "] = ");
if (bytes.length > 0) {
int len = Math.min(bytes.length, 20);
buf.append(bytes[0]);
for (int i = 1; i < len; i++) {
buf.append(",");
buf.append(bytes[i]);
}
if (bytes.length > 20) {
buf.append("...");
}
}
return buf.toString();
}
return "";
}
Object getValue(Record rec, int col) {
switch (type) {
case BYTE:
return new Byte(rec.getByteValue(col));
case BOOLEAN:
return Boolean.valueOf(rec.getBooleanValue(col));
case SHORT:
return new Short(rec.getShortValue(col));
case INT:
return new Integer(rec.getIntValue(col));
case LONG:
return "0x" + Long.toHexString(rec.getLongValue(col));
//return new Long(rec.getLongValue(col));
case STRING:
return " " + rec.getString(col);
case BINARY:
byte[] bytes = rec.getBinaryData(col);
StringBuffer buf = new StringBuffer(" byte[" + bytes.length + "] = ");
if (bytes.length > 0) {
int len = Math.min(bytes.length, 20);
String str = getByteString(bytes[0]);
buf.append(str);
for (int i = 1; i < len; i++) {
buf.append(",");
buf.append(getByteString(bytes[i]));
}
if (bytes.length > 20) {
buf.append("...");
}
}
return buf.toString();
}
return "";
}
private String getByteString(byte b) {
String str = Integer.toHexString(b);
if (str.length() > 2) {
str = str.substring(str.length() - 2);
}
return "0x" + str;
}
// private String format(long l, int size) {
// String hex = Long.toHexString(l);
// if (hex.length() > size) {
// hex = hex.substring(hex.length()-size);
// }
// else if (hex.length() < size) {
// StringBuffer b = new StringBuffer(20);
// for(int i=hex.length();i<size;i++) {
// b.append("");
// }
// b.append(hex);
// hex = b.toString();
// }
//
// return hex;
// }
}
class DbSmallTableModel implements TableModel {
ArrayList<TableModelListener> listeners = new ArrayList<>();
Table table;
Schema schema;
ColumnAdapter[] colAdapters;
ColumnAdapter keyAdapter;
Record[] records;
DbSmallTableModel(Table table) {
this.table = table;
schema = table.getSchema();
records = new Record[table.getRecordCount()];
keyAdapter = new ColumnAdapter(schema.getKeyFieldClass());
colAdapters = new ColumnAdapter[schema.getFieldCount()];
Class<?>[] classes = schema.getFieldClasses();
for (int i = 0; i < colAdapters.length; i++) {
colAdapters[i] = new ColumnAdapter(classes[i]);
}
try {
RecordIterator it = table.iterator();
for (int i = 0; i < records.length; i++) {
records[i] = it.next();
}
}
catch (IOException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#addTableModelListener(javax.swing.event.TableModelListener)
*/
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnClass(int)
*/
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return keyAdapter.getValueClass();
}
return colAdapters[columnIndex - 1].getValueClass();
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnCount()
*/
@Override
public int getColumnCount() {
return schema.getFieldCount() + 1;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnName(int)
*/
@Override
public String getColumnName(int columnIndex) {
if (columnIndex == 0) {
return schema.getKeyName();
}
--columnIndex;
int[] indexCols = table.getIndexedColumns();
boolean isIndexed = false;
for (int indexCol : indexCols) {
if (indexCol == columnIndex) {
isIndexed = true;
break;
}
}
return schema.getFieldNames()[columnIndex] + (isIndexed ? "*" : "");
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getRowCount()
*/
@Override
public int getRowCount() {
return table.getRecordCount();
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getValueAt(int, int)
*/
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Record rec = records[rowIndex];
if (columnIndex == 0) {
return keyAdapter.getKeyValue(rec);
}
return colAdapters[columnIndex - 1].getValue(rec, columnIndex - 1);
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#isCellEditable(int, int)
*/
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#removeTableModelListener(javax.swing.event.TableModelListener)
*/
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
*/
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
}
class DbLargeTableModel implements TableModel {
ArrayList<TableModelListener> listeners = new ArrayList<>();
Table table;
Schema schema;
ColumnAdapter keyAdapter;
ColumnAdapter[] colAdapters;
RecordIterator recIt;
Record lastRecord;
int lastIndex;
Field minKey;
Field maxKey;
Field keyType;
DbLargeTableModel(Table table) {
this.table = table;
schema = table.getSchema();
keyAdapter = new ColumnAdapter(schema.getKeyFieldClass());
try {
keyType = schema.getKeyFieldClass().newInstance();
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
try {
recIt = table.iterator();
lastRecord = recIt.next();
lastIndex = 0;
findMaxKey();
findMinKey();
}
catch (IOException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
colAdapters = new ColumnAdapter[schema.getFieldCount()];
Class<?>[] classes = schema.getFieldClasses();
for (int i = 0; i < colAdapters.length; i++) {
colAdapters[i] = new ColumnAdapter(classes[i]);
}
}
private void findMinKey() throws IOException {
RecordIterator iter = table.iterator();
Record rec = iter.next();
minKey = rec.getKeyField();
}
private void findMaxKey() throws IOException {
Field max = keyType.newField();
if (table.useLongKeys()) {
max.setLongValue(Long.MAX_VALUE);
}
else {
byte[] maxBytes = new byte[128];
Arrays.fill(maxBytes, 0, 128, (byte) 0x7f);
max.setBinaryData(maxBytes);
}
RecordIterator iter = table.iterator(max);
Record rec = iter.previous();
maxKey = rec.getKeyField();
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#addTableModelListener(javax.swing.event.TableModelListener)
*/
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnClass(int)
*/
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return keyAdapter.getValueClass();
}
return colAdapters[columnIndex - 1].getValueClass();
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnCount()
*/
@Override
public int getColumnCount() {
return schema.getFieldCount() + 1;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnName(int)
*/
@Override
public String getColumnName(int columnIndex) {
if (columnIndex == 0) {
return schema.getKeyName();
}
--columnIndex;
int[] indexCols = table.getIndexedColumns();
boolean isIndexed = false;
for (int indexCol : indexCols) {
if (indexCol == columnIndex) {
isIndexed = true;
break;
}
}
return schema.getFieldNames()[columnIndex] + (isIndexed ? "*" : "");
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getRowCount()
*/
@Override
public int getRowCount() {
return table.getRecordCount();
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getValueAt(int, int)
*/
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Record rec = getRecord(rowIndex);
if (rec == null) {
return null;
}
if (columnIndex == 0) {
return keyAdapter.getKeyValue(rec);
}
return colAdapters[columnIndex - 1].getValue(rec, columnIndex - 1);
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#isCellEditable(int, int)
*/
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#removeTableModelListener(javax.swing.event.TableModelListener)
*/
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
*/
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
private Record getRecord(int index) {
try {
if (index == lastIndex + 1) {
if (!recIt.hasNext()) {
// do something
}
lastRecord = recIt.next();
lastIndex = index;
}
else if (index != lastIndex) {
if (index < lastIndex && (lastIndex - index) < 200) {
int backup = lastIndex - index + 1;
for (int i = 0; i < backup; i++) {
if (recIt.hasPrevious()) {
recIt.previous();
}
}
lastRecord = recIt.next();
lastIndex = index;
}
else {
findRecord(index);
lastRecord = recIt.next();
lastIndex = index;
}
}
}
catch (IOException e) {
// XXX Auto-generated catch block
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
return lastRecord;
}
private void findRecord(int index) throws IOException {
if (index < 1000) {
recIt = table.iterator();
for (int i = 0; i < index; i++) {
recIt.next();
}
}
else if (index > table.getRecordCount() - 1000) {
recIt = table.iterator(maxKey);
if (recIt.hasNext()) {
recIt.next();
}
for (int i = 0; i < table.getRecordCount() - index; i++) {
recIt.previous();
}
}
else {
recIt = table.iterator(approxKey(index));
}
}
private Field approxKey(int index) {
Field key = keyType.newField();
if (table.useLongKeys()) {
long min = minKey.getLongValue();
long max = maxKey.getLongValue();
long k = min + ((max - min) * index / table.getRecordCount());
key.setLongValue(k);
}
else {
long min = getLong(minKey.getBinaryData());
long max = getLong(maxKey.getBinaryData());
long k = min + ((max - min) * index / table.getRecordCount());
byte[] bytes = new byte[8];
for (int i = 7; i >= 0; i--) {
bytes[i] = (byte) k;
k >>= 8;
}
key.setBinaryData(bytes);
}
return key;
}
private long getLong(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return 0;
}
long value = 0;
for (int i = 0; i < 8; i++) {
value <<= 8;
if (i < bytes.length) {
value += bytes[i] & 0xff;
}
}
return value;
}
}