mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-1593 fixed selection bug in bytebiewer where last byte in memory block could not be selected. Also fixed issue when starting/ending a selection in a separator line.
This commit is contained in:
parent
a9baf9f6d8
commit
618bd70cf5
7 changed files with 189 additions and 163 deletions
|
@ -325,9 +325,6 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
addFieldMouseListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the FontMetrics; recreate the fields.
|
||||
*/
|
||||
void setFontMetrics(FontMetrics fm) {
|
||||
this.fm = fm;
|
||||
createFields();
|
||||
|
@ -336,6 +333,7 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
|
||||
/**
|
||||
* Set the color used to denote changes in the byte block.
|
||||
* @param c the color for unsaved changed byte values
|
||||
*/
|
||||
void setEditColor(Color c) {
|
||||
editColor = c;
|
||||
|
@ -386,15 +384,13 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the color used to denote changes in the byte block.
|
||||
* Get the the color of unsaved byte changes
|
||||
* @return the the color of unsaved byte changes
|
||||
*/
|
||||
Color getEditColor() {
|
||||
return editColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the byte blocks for displaying data.
|
||||
*/
|
||||
void setIndexMap(IndexMap map) {
|
||||
updatingIndexMap = true;
|
||||
indexMap = map;
|
||||
|
@ -437,9 +433,6 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
layoutModel.setIndexMap(indexMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection.
|
||||
*/
|
||||
void setViewerSelection(ByteBlockSelection selection) {
|
||||
removeFieldSelectionListener(this);
|
||||
try {
|
||||
|
@ -547,7 +540,7 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
return characterOffset;
|
||||
}
|
||||
|
||||
int column = characterOffset;
|
||||
int column = fieldLoc.getCol() + characterOffset;
|
||||
int fieldNum = fieldLoc.getFieldNum();
|
||||
int fieldRow = fieldLoc.getRow();
|
||||
ByteField field = (ByteField) layout.getField(fieldNum);
|
||||
|
@ -604,9 +597,6 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
return processFieldSelection(hl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the view.
|
||||
*/
|
||||
void returnToView(ByteBlock block, BigInteger index, ViewerPosition vpos) {
|
||||
FieldLocation fieldLoc = indexMap.getFieldLocation(block, index, fieldFactories);
|
||||
setViewerPosition(vpos.getIndex(), vpos.getXOffset(), vpos.getYOffset());
|
||||
|
@ -651,9 +641,6 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
return new ByteBlockInfo(block, offset, loc.getCol());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data format model.
|
||||
*/
|
||||
DataFormatModel getDataModel() {
|
||||
return model;
|
||||
}
|
||||
|
@ -683,9 +670,6 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this view is in edit mode.
|
||||
*/
|
||||
boolean getEditMode() {
|
||||
return editMode;
|
||||
}
|
||||
|
@ -780,18 +764,52 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
layoutModel.setFactorys(fieldFactories, model, charWidth);
|
||||
}
|
||||
|
||||
private ByteBlockInfo getBlockInfo(FieldLocation loc, boolean isStart) {
|
||||
private ByteBlockInfo getBlockInfoForSelectionStart(FieldLocation loc) {
|
||||
BigInteger index = loc.getIndex();
|
||||
int offset = indexMap.getFieldOffset(index, loc.getFieldNum(), fieldFactories);
|
||||
if (!isStart && loc.getCol() == 0) {
|
||||
offset--;
|
||||
if (offset < 0) {
|
||||
index = index.subtract(BigInteger.ONE);
|
||||
offset = indexMap.getFieldOffset(index, fieldFactories.length, fieldFactories);
|
||||
offset += model.getUnitByteSize() - 1;
|
||||
int fieldNum = loc.getFieldNum();
|
||||
|
||||
// if the selection starts on a separator line, skip to the next beginning of the next line
|
||||
if (indexMap.isBlockSeparatorIndex(index)) {
|
||||
index = index.add(BigInteger.ONE);
|
||||
fieldNum = 0;
|
||||
}
|
||||
|
||||
int offset = indexMap.getFieldOffset(index, fieldNum, fieldFactories);
|
||||
return indexMap.getBlockInfo(index, offset);
|
||||
}
|
||||
|
||||
private ByteBlockInfo getBlockInfoForSelectionEnd(FieldLocation loc) {
|
||||
BigInteger lineIndex = loc.getIndex();
|
||||
int fieldNum = loc.getFieldNum();
|
||||
|
||||
// if the selection ends on a separator line, go back to the end of the previous line
|
||||
if (indexMap.isBlockSeparatorIndex(lineIndex)) {
|
||||
lineIndex = lineIndex.subtract(BigInteger.ONE);
|
||||
fieldNum = fieldFactories.length - 1; // set to end of line factory
|
||||
}
|
||||
|
||||
// if the selection is before the characters in this field, the selection doesn't include
|
||||
// this field, so move back a field. (Which may require moving back to the end of the
|
||||
// previous line)
|
||||
if (loc.getCol() == 0) {
|
||||
if (--fieldNum < 0) {
|
||||
lineIndex = lineIndex.subtract(BigInteger.ONE);
|
||||
if (indexMap.isBlockSeparatorIndex(lineIndex)) {
|
||||
lineIndex = lineIndex.subtract(BigInteger.ONE);
|
||||
}
|
||||
fieldNum = fieldFactories.length - 1; // set to end of line factory
|
||||
}
|
||||
}
|
||||
return indexMap.getBlockInfo(index, offset);
|
||||
|
||||
// get the byte offset for the first byte in the field
|
||||
int bytesFromLineStart = indexMap.getFieldOffset(lineIndex, fieldNum, fieldFactories);
|
||||
|
||||
// extend the selection to include all bytes in the selected end field since we don't
|
||||
// currently support partial field selections
|
||||
int bytesInField = model.getUnitByteSize();
|
||||
int lastByteInSelectionOnLine = bytesFromLineStart + bytesInField - 1;
|
||||
|
||||
return indexMap.getBlockInfo(lineIndex, lastByteInSelectionOnLine);
|
||||
}
|
||||
|
||||
private void addByteBlockRange(ByteBlockSelection sel, ByteBlockInfo start, ByteBlockInfo end) {
|
||||
|
@ -820,21 +838,23 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a byte block selection from the field selection.
|
||||
* Translates a screen/view selection into a byte block model selection
|
||||
* @param fieldSelection a {@link FieldPanel} selection
|
||||
* @return a {@link ByteBlockSelection}
|
||||
*/
|
||||
protected ByteBlockSelection processFieldSelection(FieldSelection selection) {
|
||||
protected ByteBlockSelection processFieldSelection(FieldSelection fieldSelection) {
|
||||
|
||||
ByteBlockSelection sel = new ByteBlockSelection();
|
||||
int count = selection.getNumRanges();
|
||||
ByteBlockSelection blockSelection = new ByteBlockSelection();
|
||||
int count = fieldSelection.getNumRanges();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
FieldRange fr = selection.getFieldRange(i);
|
||||
ByteBlockInfo startInfo = getBlockInfo(fr.getStart(), true);
|
||||
ByteBlockInfo endInfo = getBlockInfo(fr.getEnd(), false);
|
||||
addByteBlockRange(sel, startInfo, endInfo);
|
||||
FieldRange range = fieldSelection.getFieldRange(i);
|
||||
ByteBlockInfo start = getBlockInfoForSelectionStart(range.getStart());
|
||||
ByteBlockInfo end = getBlockInfoForSelectionEnd(range.getEnd());
|
||||
addByteBlockRange(blockSelection, start, end);
|
||||
}
|
||||
|
||||
return sel;
|
||||
return blockSelection;
|
||||
}
|
||||
|
||||
String getTextForSelection() {
|
||||
|
@ -846,9 +866,6 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
|||
return FieldSelectionHelper.getAllSelectedText(selection, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field location for the given block, offset.
|
||||
*/
|
||||
FieldLocation getFieldLocation(ByteBlock block, BigInteger offset) {
|
||||
return indexMap.getFieldLocation(block, offset, fieldFactories);
|
||||
}
|
||||
|
|
|
@ -163,7 +163,6 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
|
|||
* Notification that an option changed.
|
||||
*
|
||||
* @param options options object containing the property that changed
|
||||
* @param group
|
||||
* @param optionName name of option that changed
|
||||
* @param oldValue old value of the option
|
||||
* @param newValue new value of the option
|
||||
|
|
|
@ -85,9 +85,6 @@ public class ByteViewerPanel extends JPanel
|
|||
|
||||
private List<AddressSetDisplayListener> displayListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected ByteViewerPanel(ByteViewerComponentProvider provider) {
|
||||
super();
|
||||
this.provider = provider;
|
||||
|
@ -181,9 +178,6 @@ public class ByteViewerPanel extends JPanel
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
// ** package-level methods **
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Set the cursor color that indicates the view that has focus.
|
||||
*/
|
||||
void setCurrentCursorColor(Color c) {
|
||||
currentCursorColor = c;
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
|
@ -223,9 +217,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color that indicates gaps in memory.
|
||||
*/
|
||||
void setSeparatorColor(Color c) {
|
||||
indexFactory.setMissingValueColor(c);
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
|
@ -234,9 +225,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color of the cursor when the byte viewer is not in focus.
|
||||
*/
|
||||
void setNonFocusCursorColor(Color c) {
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
ByteViewerComponent comp = viewList.get(i);
|
||||
|
@ -247,6 +235,7 @@ public class ByteViewerPanel extends JPanel
|
|||
/**
|
||||
* Set the byte blocks and create an new IndexMap object that will be passed to the index panel
|
||||
* and to each component that shows a format.
|
||||
* @param blockSet the set of blocks
|
||||
*/
|
||||
void setByteBlocks(ByteBlockSet blockSet) {
|
||||
this.blockSet = blockSet;
|
||||
|
@ -261,7 +250,7 @@ public class ByteViewerPanel extends JPanel
|
|||
startField.setText(start);
|
||||
ByteBlock lastBlock = blocks[blocks.length - 1];
|
||||
endField.setText(lastBlock
|
||||
.getLocationRepresentation(lastBlock.getLength().subtract(BigInteger.ONE)));
|
||||
.getLocationRepresentation(lastBlock.getLength().subtract(BigInteger.ONE)));
|
||||
|
||||
indexPanelWidth = getIndexPanelWidth(blocks);
|
||||
int center = indexPanelWidth / 2;
|
||||
|
@ -295,9 +284,6 @@ public class ByteViewerPanel extends JPanel
|
|||
indexSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection for all the views.
|
||||
*/
|
||||
void setViewerSelection(ByteBlockSelection selection) {
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
ByteViewerComponent c = viewList.get(i);
|
||||
|
@ -305,11 +291,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current selection.
|
||||
*
|
||||
* @return ByteBlockSelection selection, or null if there is no selection
|
||||
*/
|
||||
ByteBlockSelection getViewerSelection() {
|
||||
if (currentView == null) {
|
||||
return null;
|
||||
|
@ -317,9 +298,6 @@ public class ByteViewerPanel extends JPanel
|
|||
return currentView.getViewerSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the highlight for all the views.
|
||||
*/
|
||||
void setViewerHighlight(ByteBlockSelection highlight) {
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
ByteViewerComponent c = viewList.get(i);
|
||||
|
@ -327,9 +305,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the background color model for all the views.
|
||||
*/
|
||||
public void setViewerBackgroundColorModel(BackgroundColorModel colorModel) {
|
||||
for (ByteViewerComponent c : viewList) {
|
||||
c.setBackgroundColorModel(colorModel);
|
||||
|
@ -365,6 +340,7 @@ public class ByteViewerPanel extends JPanel
|
|||
|
||||
/**
|
||||
* Get the cursor location. If there is no current view, then return null.
|
||||
* @return The ByteBlockInfo which describes the a location in the byte block domain
|
||||
*/
|
||||
ByteBlockInfo getCursorLocation() {
|
||||
if (currentView == null) {
|
||||
|
@ -385,9 +361,6 @@ public class ByteViewerPanel extends JPanel
|
|||
return currentView.getDataModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently focused view.
|
||||
*/
|
||||
public ByteViewerComponent getCurrentComponent() {
|
||||
return currentView;
|
||||
}
|
||||
|
@ -403,6 +376,7 @@ public class ByteViewerPanel extends JPanel
|
|||
* @param model model that understands the format
|
||||
* @param editMode true if edit mode is on
|
||||
* @param updateViewPosition true if the view position should be set
|
||||
* @return the new component
|
||||
*/
|
||||
ByteViewerComponent addView(String viewName, DataFormatModel model, boolean editMode,
|
||||
boolean updateViewPosition) {
|
||||
|
@ -464,9 +438,6 @@ public class ByteViewerPanel extends JPanel
|
|||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the view that currently has focus.
|
||||
*/
|
||||
void removeView(ByteViewerComponent comp) {
|
||||
|
||||
viewList.remove(comp);
|
||||
|
@ -485,10 +456,6 @@ public class ByteViewerPanel extends JPanel
|
|||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given component to be the current view; called by the mouse listener in the
|
||||
* ByteViewerComponent when the user clicks in the panel.
|
||||
*/
|
||||
void setCurrentView(ByteViewerComponent c) {
|
||||
if (currentView != null && currentView != c) {
|
||||
currentView.setFocusedCursorColor(provider.getCursorColor());
|
||||
|
@ -496,9 +463,6 @@ public class ByteViewerPanel extends JPanel
|
|||
currentView = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cursor color on the current view to show that it is in edit mode.
|
||||
*/
|
||||
void setEditMode(boolean editMode) {
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
ByteViewerComponent c = viewList.get(i);
|
||||
|
@ -506,10 +470,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the current view is in edit mode.
|
||||
*
|
||||
*/
|
||||
boolean getEditMode() {
|
||||
if (currentView == null) {
|
||||
return false;
|
||||
|
@ -531,16 +491,10 @@ public class ByteViewerPanel extends JPanel
|
|||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of views that is currently displayed.
|
||||
*/
|
||||
int getNumberOfViews() {
|
||||
return viewList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block offset.
|
||||
*/
|
||||
void setOffset(int offset) {
|
||||
if (blockOffset != offset) {
|
||||
blockOffset = offset;
|
||||
|
@ -549,9 +503,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bytes per line. Bytes per line dictates the number of fields displayed in a row.
|
||||
*/
|
||||
void setBytesPerLine(int bytesPerLine) {
|
||||
|
||||
if (this.bytesPerLine != bytesPerLine) {
|
||||
|
@ -568,6 +519,7 @@ public class ByteViewerPanel extends JPanel
|
|||
|
||||
/**
|
||||
* Check that each model for the views can support the given bytes per line value.
|
||||
* @param numBytesPerLine the bytes per line value to see if supported
|
||||
*
|
||||
* @throws InvalidInputException if a model cannot support the bytesPerLine value
|
||||
*/
|
||||
|
@ -662,9 +614,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the font metrics that all viewer components are using.
|
||||
*/
|
||||
FontMetrics getCurrentFontMetrics() {
|
||||
return fm;
|
||||
}
|
||||
|
@ -672,6 +621,7 @@ public class ByteViewerPanel extends JPanel
|
|||
/**
|
||||
* Return array of names of views in the order that they appear in the panel. The name array
|
||||
* includes an entry for the index panel.
|
||||
* @return a DataModelInfo object that describes the current views
|
||||
*/
|
||||
DataModelInfo getDataModelInfo() {
|
||||
|
||||
|
@ -710,10 +660,7 @@ public class ByteViewerPanel extends JPanel
|
|||
indexPanel.setViewerPosition(pos.getIndex(), pos.getXOffset(), pos.getYOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the view.
|
||||
*/
|
||||
void returnToView(ByteViewerState vp) {
|
||||
void restoreView(ByteViewerState vp) {
|
||||
if (currentView == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -740,9 +687,6 @@ public class ByteViewerPanel extends JPanel
|
|||
setEditColor(newEditColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the bytes per line and offset values.
|
||||
*/
|
||||
void restoreConfigState(int newBytesPerLine, int offset) {
|
||||
if (blockOffset != offset) {
|
||||
blockOffset = offset;
|
||||
|
@ -759,9 +703,6 @@ public class ByteViewerPanel extends JPanel
|
|||
refreshView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the font metrics.
|
||||
*/
|
||||
void setFontMetrics(FontMetrics fm) {
|
||||
this.fm = fm;
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
|
@ -781,9 +722,6 @@ public class ByteViewerPanel extends JPanel
|
|||
indexPanel.modelSizeChanged(IndexMapper.IDENTITY_MAPPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color used to denote changes in the byte block.
|
||||
*/
|
||||
void setEditColor(Color editColor) {
|
||||
this.editColor = editColor;
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
|
@ -792,9 +730,6 @@ public class ByteViewerPanel extends JPanel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the font metrics that the panel is using.
|
||||
*/
|
||||
protected FontMetrics getFontMetrics() {
|
||||
return fm;
|
||||
}
|
||||
|
@ -1013,9 +948,6 @@ public class ByteViewerPanel extends JPanel
|
|||
return maxWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see docking.widgets.fieldpanel.LayoutModel#getIndexAfter(int)
|
||||
*/
|
||||
@Override
|
||||
public BigInteger getIndexAfter(BigInteger index) {
|
||||
BigInteger nextIndex = index.add(BigInteger.ONE);
|
||||
|
@ -1025,9 +957,6 @@ public class ByteViewerPanel extends JPanel
|
|||
return nextIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see docking.widgets.fieldpanel.LayoutModel#getIndexBefore(int)
|
||||
*/
|
||||
@Override
|
||||
public BigInteger getIndexBefore(BigInteger index) {
|
||||
if (index.equals(BigInteger.ZERO)) {
|
||||
|
@ -1036,13 +965,6 @@ public class ByteViewerPanel extends JPanel
|
|||
return index.subtract(BigInteger.ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see docking.widgets.fieldpanel.LayoutModel#changePending()
|
||||
*/
|
||||
public boolean changePending() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* Getter for the list of ByteViewer Components
|
||||
*
|
||||
|
|
|
@ -80,6 +80,22 @@ class FieldFactory {
|
|||
return startX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this FieldFactory will return a non-null value at the given line index.
|
||||
* If the index is the first index for a block, then there may be non active fields at the
|
||||
* beginning of the line. Similarly, the last line of a block may have inactive fields at
|
||||
* the end of the line.
|
||||
*
|
||||
* @param index the line index
|
||||
* @return true if this FieldFactory will produce a non-null value at the given line index.
|
||||
*/
|
||||
public boolean isActive(BigInteger index) {
|
||||
if (indexMap == null) {
|
||||
return false;
|
||||
}
|
||||
return indexMap.getBlockInfo(index, fieldOffset) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Field object for the given index.
|
||||
* This method is called for the given index and the fieldOffset
|
||||
|
@ -92,7 +108,7 @@ class FieldFactory {
|
|||
// translate index to block and offset into the block
|
||||
ByteBlockInfo info = indexMap.getBlockInfo(index, fieldOffset);
|
||||
if (info == null) {
|
||||
if (indexMap.showSeparator(index)) {
|
||||
if (indexMap.isBlockSeparatorIndex(index)) {
|
||||
ByteField bf = new ByteField(noValueStr, fm, startX, width, false, fieldOffset,
|
||||
index, highlightFactory);
|
||||
bf.setForeground(separatorColor);
|
||||
|
|
|
@ -73,7 +73,7 @@ class IndexFieldFactory {
|
|||
}
|
||||
}
|
||||
if (info == null) {
|
||||
if (indexMap.showSeparator(index)) {
|
||||
if (indexMap.isBlockSeparatorIndex(index)) {
|
||||
SimpleTextField sf =
|
||||
new SimpleTextField(noValueStr, fm, startX, width, false, highlightFactory);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,12 +15,11 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.byteviewer;
|
||||
|
||||
import ghidra.app.plugin.core.format.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.plugin.core.format.*;
|
||||
|
||||
/**
|
||||
* Generates a map between bytes in memory and indexes. Extra indexes are inserted to
|
||||
|
@ -42,6 +40,11 @@ public class IndexMap {
|
|||
/**
|
||||
* Create an IndexMap with the given set of blocks, the bytes per line, and the user
|
||||
* set blockOffset.
|
||||
* @param blockSet the set of byte blocks
|
||||
* @param bytesPerLine the number of bytes displayed per line
|
||||
* @param blockOffset the number of byte positions to skip when rendering the first line of
|
||||
* the block. (If a block starts at address 6, we skip 6 byte positions so the entire block
|
||||
* is positioned as if the block started at 0
|
||||
*/
|
||||
IndexMap(ByteBlockSet blockSet, int bytesPerLine, int blockOffset) {
|
||||
|
||||
|
@ -57,8 +60,9 @@ public class IndexMap {
|
|||
BigInteger blockEnd = blockStart.add(blocks[i].getLength());
|
||||
int remainder = blockEnd.remainder(bytesInLine).intValue();
|
||||
BigInteger endIndex =
|
||||
remainder == 0 ? blockEnd : blockEnd.add(BigInteger.valueOf(bytesPerLine -
|
||||
remainder));
|
||||
remainder == 0 ? blockEnd
|
||||
: blockEnd.add(BigInteger.valueOf(bytesPerLine -
|
||||
remainder));
|
||||
BigInteger endLayoutIndex = endIndex.divide(bytesInLine);
|
||||
BlockInfo info = new BlockInfo(blocks[i], nextStart, blockStart, blockEnd, endIndex);
|
||||
blockInfoMap.put(endLayoutIndex, info);
|
||||
|
@ -73,6 +77,9 @@ public class IndexMap {
|
|||
|
||||
/**
|
||||
* Returns the total number of indexes in this map.
|
||||
* @return The number byte indexes (possible display positions) in this index map (includes
|
||||
* offset padding and separator positions. This will always be a muliple of the number of
|
||||
* bytes displayed per line.
|
||||
*/
|
||||
BigInteger getNumIndexes() {
|
||||
return numIndexes;
|
||||
|
@ -80,6 +87,7 @@ public class IndexMap {
|
|||
|
||||
/**
|
||||
* Returns the number of bytes per line.
|
||||
* @return the number of bytes per line
|
||||
*/
|
||||
int getBytesPerLine() {
|
||||
return bytesInLine.intValue();
|
||||
|
@ -87,6 +95,10 @@ public class IndexMap {
|
|||
|
||||
/**
|
||||
* Returns block location information about the given index and fieldOffset.
|
||||
* @param index The line index
|
||||
* @param fieldOffset the field offset (in bytes) from the beginning of the line.
|
||||
* @return The ByteBlockInfo object that contains the block and offset into that block
|
||||
* that is the resulting byte value.
|
||||
*/
|
||||
ByteBlockInfo getBlockInfo(BigInteger index, int fieldOffset) {
|
||||
SortedMap<BigInteger, BlockInfo> tailMap = blockInfoMap.tailMap(index);
|
||||
|
@ -104,15 +116,21 @@ public class IndexMap {
|
|||
|
||||
/**
|
||||
* Returns true if the given index is between blocks.
|
||||
* @param index the index to check if it is a block separator index
|
||||
* @return true if the given index is between blocks.
|
||||
*/
|
||||
boolean showSeparator(BigInteger index) {
|
||||
boolean isBlockSeparatorIndex(BigInteger index) {
|
||||
return blockInfoMap.containsKey(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a field location for the given block, offset.
|
||||
* @param block the ByteBlock containing the byte to get a FieldLocation for
|
||||
* @param offset the byte offset in the block
|
||||
* @param factories that generated values for a line
|
||||
* @return the field location for the given byte location
|
||||
*/
|
||||
FieldLocation getFieldLocation(ByteBlock block, BigInteger offset, FieldFactory[] factorys) {
|
||||
FieldLocation getFieldLocation(ByteBlock block, BigInteger offset, FieldFactory[] factories) {
|
||||
for (BlockInfo blockInfo : blockInfoMap.values()) {
|
||||
if (blockInfo.block == block) {
|
||||
BigInteger byteIndex = blockInfo.blockStart.add(offset);
|
||||
|
@ -120,52 +138,106 @@ public class IndexMap {
|
|||
int lineOffset = byteIndex.remainder(bytesInLine).intValue();
|
||||
|
||||
//int fieldOffset = lineOffset / fields.length;
|
||||
int nbytesPerField = bytesInLine.intValue() / factorys.length;
|
||||
int nbytesPerField = bytesInLine.intValue() / factories.length;
|
||||
int fieldOffset = (lineOffset / nbytesPerField) * nbytesPerField;
|
||||
|
||||
int byteOffset = lineOffset % nbytesPerField;
|
||||
|
||||
int fieldNum = getFieldNum(index, fieldOffset, factorys);
|
||||
int col = factorys[fieldNum].getColumnPosition(block, byteOffset);
|
||||
int fieldNum = getFieldNum(index, fieldOffset, factories);
|
||||
int col = factories[fieldNum].getColumnPosition(block, byteOffset);
|
||||
return new FieldLocation(index, fieldNum, 0, col);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int getFieldOffset(BigInteger index, int fieldNum, FieldFactory[] factorys) {
|
||||
int numFields = 0;
|
||||
for (int i = 0; i < factorys.length; i++) {
|
||||
ByteField bf = (ByteField) factorys[i].getField(index);
|
||||
if (bf != null) {
|
||||
if (numFields == fieldNum) {
|
||||
return factorys[i].getFieldOffset();
|
||||
}
|
||||
numFields++;
|
||||
/**
|
||||
* Returns the index of the first factory that is active for a given index
|
||||
* @param index the line index
|
||||
* @param factories the list of factories that generate values on a line
|
||||
* @return the index of the first active factory on that line. This will be 0 except for
|
||||
* the first line of a block which may start part way in the line.
|
||||
*/
|
||||
int getFirstActiveFactoryIndex(BigInteger index, FieldFactory[] factories) {
|
||||
for (int i = 0; i < factories.length; i++) {
|
||||
if (factories[i].isActive(index)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return (numFields > 0) ? factorys[numFields - 1].getFieldOffset() : 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int getFieldNum(BigInteger index, int fieldOffset, FieldFactory[] factorys) {
|
||||
int fieldNum = 0;
|
||||
for (int j = 0; j < factorys.length; j++) {
|
||||
ByteField bf = (ByteField) factorys[j].getField(index);
|
||||
if (bf != null) {
|
||||
if (bf.getFieldOffset() == fieldOffset) {
|
||||
break;
|
||||
}
|
||||
fieldNum++;
|
||||
/**
|
||||
* Returns the index of the last factory that is active for a given index
|
||||
* @param index the line index
|
||||
* @param factories the list of factories that generate values on a line
|
||||
* @return the index of the last active factory on that line. This will be factories.length
|
||||
* except for the last line of a block which may end part way in the line.
|
||||
*/
|
||||
int getLastActiveFactoryIndex(BigInteger index, FieldFactory[] factories) {
|
||||
for (int i = factories.length - 1; i > 0; i--) {
|
||||
if (factories[i].isActive(index)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (fieldNum >= factorys.length) {
|
||||
fieldNum = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field offset (byte offset from the beginning of the line) for the given index
|
||||
* and fieldNum.
|
||||
* @param lineIndex the line index to get the field offset. This only matters because some indexes
|
||||
* don't use all the fields and have blanks in some of the factory field locations. Fieldnum
|
||||
* starts counting from the first visible field.
|
||||
* @param fieldNum the index of the field to get an offset for. This is complicated by the
|
||||
* fact that fieldNum is 0 for the first visible field.
|
||||
* @param factories the list of factories that generate byte fields per line. The factories
|
||||
* are identical except for which offset it uses to get its bytes for display.
|
||||
* @return the byte offset from the byte that would be shown at the beginning of the line
|
||||
*/
|
||||
int getFieldOffset(BigInteger lineIndex, int fieldNum, FieldFactory[] factories) {
|
||||
int firstActiveFactoryIndex = getFirstActiveFactoryIndex(lineIndex, factories);
|
||||
if (firstActiveFactoryIndex < 0) {
|
||||
return 0;
|
||||
}
|
||||
return fieldNum;
|
||||
int lastActiveFactoryIndex = getLastActiveFactoryIndex(lineIndex, factories);
|
||||
int factoryIndex = firstActiveFactoryIndex + fieldNum;
|
||||
if (factoryIndex <= lastActiveFactoryIndex) {
|
||||
return factories[factoryIndex].getFieldOffset();
|
||||
}
|
||||
return factories[lastActiveFactoryIndex].getFieldOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets field factory index for the given fieldOffset, adjusting for inactive fields such
|
||||
* that the first active field has a fieldNum of 0. For example, if the group size is 2 and
|
||||
* bytes per line is 8,then the factories have fieldOffsets of 0,2,4,6. So if all fields are
|
||||
* visible, the fieldNum for 4 is 2. But if the first field is non active, then the offset of
|
||||
* 4 maps to fieldNum of 1.
|
||||
* @param lineIndex the line index to get a fieldNum for
|
||||
* @param fieldOffset the byte offset from the byte that would be displayed by the first factory
|
||||
* (the first factory always has an offset of 0)
|
||||
* @param factories the list of factories for a line
|
||||
* @return the active index of the factory that displays bytes at the given fieldOffset.
|
||||
*/
|
||||
int getFieldNum(BigInteger lineIndex, int fieldOffset, FieldFactory[] factories) {
|
||||
int firstActiveFactoryIndex = getFirstActiveFactoryIndex(lineIndex, factories);
|
||||
if (firstActiveFactoryIndex < 0) {
|
||||
return 0;
|
||||
}
|
||||
int lastActiveFactoryIndex = getLastActiveFactoryIndex(lineIndex, factories);
|
||||
for (int i = firstActiveFactoryIndex; i < lastActiveFactoryIndex; i++) {
|
||||
if (factories[i].getFieldOffset() == fieldOffset) {
|
||||
return i - firstActiveFactoryIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return lastActiveFactoryIndex - firstActiveFactoryIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BlockSet.
|
||||
* @return the BlockSet that was used to create this index map
|
||||
*/
|
||||
ByteBlockSet getByteBlockSet() {
|
||||
return blockSet;
|
||||
|
|
|
@ -316,7 +316,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
|||
if (blocks != null && blockNumber >= 0 && blockNumber < blocks.length) {
|
||||
ByteViewerState view = new ByteViewerState(blockSet,
|
||||
new ByteBlockInfo(blocks[blockNumber], blockOffset, column), vp);
|
||||
panel.returnToView(view);
|
||||
panel.restoreView(view);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -627,7 +627,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
|||
if (blocks != null && blockNumber >= 0 && blockNumber < blocks.length) {
|
||||
ByteViewerState view = new ByteViewerState(blockSet,
|
||||
new ByteBlockInfo(blocks[blockNumber], blockOffset, column), vp);
|
||||
panel.returnToView(view);
|
||||
panel.restoreView(view);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue