diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java index 3f8ecca425..fa1bf91008 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java @@ -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); } diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java index 4202146c82..9f91279c60 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java @@ -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 diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java index 13db74bbd7..f3ad5f7bbf 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java @@ -85,9 +85,6 @@ public class ByteViewerPanel extends JPanel private List 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 * diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java index 622ebf3ca6..ea5cf500c6 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java @@ -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); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java index a2e94b586a..409b14ab7a 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java @@ -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); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexMap.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexMap.java index 4b3483d009..16be6a791a 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexMap.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexMap.java @@ -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 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; diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java index e46389e2a3..07472855e9 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java @@ -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); } }