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 fa1bf91008..bf588e1ed1 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 @@ -606,6 +606,7 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene /** * Convert the cursor location to a byte block and an offset. + * @return the cursor location to a byte block and an offset. */ ByteBlockInfo getViewerCursorLocation() { FieldLocation loc = getCursorLocation(); @@ -634,11 +635,10 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene if (info == null) { return null; } - ByteBlock block = info.getBlock(); BigInteger offset = info.getOffset(); int byteOffset = model.getByteOffset(info.getBlock(), pos); offset = offset.add(BigInteger.valueOf(byteOffset)); - return new ByteBlockInfo(block, offset, loc.getCol()); + return new ByteBlockInfo(info.getBlock(), offset, loc.getCol()); } DataFormatModel getDataModel() { @@ -764,7 +764,7 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene layoutModel.setFactorys(fieldFactories, model, charWidth); } - private ByteBlockInfo getBlockInfoForSelectionStart(FieldLocation loc) { + private IndexedByteBlockInfo getBlockInfoForSelectionStart(FieldLocation loc) { BigInteger index = loc.getIndex(); int fieldNum = loc.getFieldNum(); @@ -778,7 +778,7 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene return indexMap.getBlockInfo(index, offset); } - private ByteBlockInfo getBlockInfoForSelectionEnd(FieldLocation loc) { + private IndexedByteBlockInfo getBlockInfoForSelectionEnd(FieldLocation loc) { BigInteger lineIndex = loc.getIndex(); int fieldNum = loc.getFieldNum(); @@ -812,10 +812,17 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene return indexMap.getBlockInfo(lineIndex, lastByteInSelectionOnLine); } - private void addByteBlockRange(ByteBlockSelection sel, ByteBlockInfo start, ByteBlockInfo end) { + private void addByteBlockRange(ByteBlockSelection sel, IndexedByteBlockInfo start, + IndexedByteBlockInfo end) { if (start == null || end == null) { return; } + + // this should only happen when both the start and end are on the same separator line + if (start.compareTo(end) > 0) { + return; + } + ByteBlock startBlock = start.getBlock(); ByteBlock endBlock = end.getBlock(); @@ -849,8 +856,8 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene for (int i = 0; i < count; i++) { FieldRange range = fieldSelection.getFieldRange(i); - ByteBlockInfo start = getBlockInfoForSelectionStart(range.getStart()); - ByteBlockInfo end = getBlockInfoForSelectionEnd(range.getEnd()); + IndexedByteBlockInfo start = getBlockInfoForSelectionStart(range.getStart()); + IndexedByteBlockInfo end = getBlockInfoForSelectionEnd(range.getEnd()); addByteBlockRange(blockSelection, start, end); } 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 cc5e792d65..56a201f55a 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 @@ -100,7 +100,7 @@ public class IndexMap { * @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) { + IndexedByteBlockInfo getBlockInfo(BigInteger index, int fieldOffset) { SortedMap tailMap = blockInfoMap.tailMap(index); if (tailMap.isEmpty()) { return null; @@ -109,7 +109,8 @@ public class IndexMap { BigInteger byteIndex = index.multiply(bytesInLine).add(BigInteger.valueOf(fieldOffset)); if ((byteIndex.compareTo(blockInfo.blockStart) >= 0) && (byteIndex.compareTo(blockInfo.blockEnd) < 0)) { - return new ByteBlockInfo(blockInfo.block, byteIndex.subtract(blockInfo.blockStart)); + return new IndexedByteBlockInfo(index, blockInfo.block, + byteIndex.subtract(blockInfo.blockStart), 0); } return null; } @@ -257,12 +258,12 @@ public class IndexMap { while (iterator.hasNext()) { BlockInfo next = iterator.next(); if (next.block == endBlock) { - break; + return byteBlocks; } byteBlocks.add(next.block); } - return byteBlocks; - + // didn't find the end, so the end must have been before the start, so return empty list + return List.of(); } } diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/format/IndexedByteBlockInfo.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/format/IndexedByteBlockInfo.java new file mode 100644 index 0000000000..e0fa9d0d2b --- /dev/null +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/format/IndexedByteBlockInfo.java @@ -0,0 +1,47 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.format; + +import java.math.BigInteger; + +/** + * This is a ByteBlockInfo that also includes line index information. With the extra line index + * information, this object can be ordered and therefore, can implement {@link Comparable} + */ +public class IndexedByteBlockInfo extends ByteBlockInfo + implements Comparable { + + private BigInteger lineIndex; + + public IndexedByteBlockInfo(BigInteger lineIndex, ByteBlock block, BigInteger offset, + int column) { + super(block, offset, column); + this.lineIndex = lineIndex; + } + + @Override + public int compareTo(IndexedByteBlockInfo o) { + int result = lineIndex.compareTo(o.lineIndex); + if (result == 0) { + result = getOffset().compareTo(o.getOffset()); + } + if (result == 0) { + return Integer.compare(getColumn(), o.getColumn()); + } + return result; + } + +}