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:
ghidragon 2023-03-07 15:00:46 -05:00
parent a9baf9f6d8
commit 618bd70cf5
7 changed files with 189 additions and 163 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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
*

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}