mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GT-3294 Added support for DB FixedField with improved indexing.
This commit is contained in:
parent
14d4c87ef4
commit
fcb3151f94
224 changed files with 9574 additions and 7913 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue