mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-23 12:49:45 +00:00
Merge remote-tracking branch 'origin/Ghidra_11.2'
This commit is contained in:
commit
4e1532be14
@ -17,6 +17,8 @@ package ghidra.app.plugin.core.compositeeditor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
@ -586,7 +588,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
@Override
|
||||
public DataTypeComponent add(int rowIndex, DataType dt) throws UsrException {
|
||||
String descr = rowIndex < getNumComponents() ? "Replace Component" : "Add Component";
|
||||
return viewDTM.withTransaction(descr, () -> {
|
||||
DataTypeComponent dtc = viewDTM.withTransaction(descr, () -> {
|
||||
DataType resolvedDt = viewDTM.resolve(dt, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
try {
|
||||
DataTypeInstance dti = getDropDataType(rowIndex, resolvedDt);
|
||||
@ -596,7 +598,11 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
fixSelection();
|
||||
componentEdited();
|
||||
selectionChanged();
|
||||
return dtc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -628,6 +634,10 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
else {
|
||||
dtc = viewDTM.withTransaction("Add Component", () -> insert(rowIndex, dt, dtLength));
|
||||
}
|
||||
|
||||
fixSelection();
|
||||
componentEdited();
|
||||
selectionChanged();
|
||||
return dtc;
|
||||
}
|
||||
|
||||
@ -733,10 +743,8 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
int sizeDiff = newCompSize - oldCompSize;
|
||||
|
||||
// New one is larger so check to make sure it will fit.
|
||||
if (sizeDiff > 0) {
|
||||
if (!checkForReplace(rowIndex, datatype)) {
|
||||
throw new InvalidDataTypeException(datatype.getDisplayName() + " doesn't fit.");
|
||||
}
|
||||
if (!isAtEnd(rowIndex) && sizeDiff > 0) {
|
||||
checkForReplace(rowIndex, datatype, newCompSize);
|
||||
}
|
||||
|
||||
// Replace the component at index.
|
||||
@ -811,35 +819,76 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
*
|
||||
* @param rowIndex index of the row (component).
|
||||
* @param datatype the type
|
||||
* @return true if the replace is allowed
|
||||
* @param length component length
|
||||
* @throws InvalidDataTypeException if check fails
|
||||
*/
|
||||
boolean checkForReplace(int rowIndex, DataType datatype) {
|
||||
private void checkForReplace(int rowIndex, DataType datatype, int length) throws InvalidDataTypeException {
|
||||
DataTypeComponent dtc = getComponent(rowIndex);
|
||||
if (dtc == null) {
|
||||
return false;
|
||||
throw new InvalidDataTypeException("Invalid component selection");
|
||||
}
|
||||
if (!isShowingUndefinedBytes()) {
|
||||
return true;
|
||||
if (!(viewComposite instanceof Structure struct)) {
|
||||
return;
|
||||
}
|
||||
if (struct.isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (isAtEnd(rowIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Does the new data type fit by replacing the component at index.
|
||||
|
||||
// Get the current data type at the index.
|
||||
DataTypeComponent comp = getComponent(rowIndex);
|
||||
int currentCompSize = comp.getLength();
|
||||
int newCompSize = datatype.getLength();
|
||||
int currentCompSize = dtc.getLength();
|
||||
int newCompSize = length;
|
||||
int sizeDiff = newCompSize - currentCompSize;
|
||||
int numUndefs = 0;
|
||||
|
||||
// New one is larger.
|
||||
if (sizeDiff > 0) {
|
||||
if (isAtEnd(rowIndex) || onlyUndefinedsUntilEnd(rowIndex + 1)) {
|
||||
return true;
|
||||
}
|
||||
// structure needs to have enough undefined bytes or replace fails.
|
||||
numUndefs = getNumUndefinedBytesAt(rowIndex + 1);
|
||||
|
||||
if (sizeDiff <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (sizeDiff <= numUndefs);
|
||||
|
||||
int undefinedSpaceAvail = getNumUndefinedBytesAfter(dtc);
|
||||
if (sizeDiff > undefinedSpaceAvail) {
|
||||
int spaceNeeded = sizeDiff - undefinedSpaceAvail;
|
||||
String msg = newCompSize + " byte replacement at 0x" + Integer.toHexString(dtc.getOffset());
|
||||
if (struct.getDefinedComponentAtOrAfterOffset(dtc.getOffset() + 1) == null) {
|
||||
// suggest growing structure
|
||||
int suggestedSize = getLength() + spaceNeeded;
|
||||
throw new InvalidDataTypeException(msg + " requires structure length of " + suggestedSize + "-bytes.");
|
||||
}
|
||||
// suggest insert bytes (NOTE: in the future a conflict removal/grow could be offered)
|
||||
throw new InvalidDataTypeException(msg + " requires " + spaceNeeded + " additional undefined bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of undefined bytes after the specified component.
|
||||
* The viewComposite must be a non-packed structure.
|
||||
* @param dtc datatype component
|
||||
* @return number of undefined bytes after non-packed structure component or -1 if no additional
|
||||
* defined components exist which will impead component growth or placement.
|
||||
*/
|
||||
protected final int getNumUndefinedBytesAfter(DataTypeComponent dtc) {
|
||||
if (!isShowingUndefinedBytes()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (!(viewComposite instanceof Structure struct)) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (struct.isPackingEnabled()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// TODO: May need special logic if dtc is zero-length component
|
||||
int length = getLength();
|
||||
int nextCompOffset = dtc.getEndOffset() + 1;
|
||||
if (nextCompOffset >= length) {
|
||||
return 0;
|
||||
}
|
||||
DataTypeComponent nextDefinedDtc = struct.getDefinedComponentAtOrAfterOffset(nextCompOffset);
|
||||
int nextDefinedOffset = (nextDefinedDtc == null) ? length : nextDefinedDtc.getOffset();
|
||||
return Math.max(0, nextDefinedOffset - nextCompOffset); // prevent negative return value
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1013,34 +1062,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of undefined bytes that are available in the structure
|
||||
* beginning at the specified row index.
|
||||
*
|
||||
* @param rowIndex the index of the row
|
||||
* @return the number of bytes
|
||||
*/
|
||||
protected int getNumUndefinedBytesAt(int rowIndex) {
|
||||
int numRowComponents = getNumComponents();
|
||||
if (rowIndex < 0 || rowIndex >= numRowComponents) {
|
||||
return 0;
|
||||
}
|
||||
DataTypeComponent startComponent = getComponent(rowIndex);
|
||||
int previousOffset = (startComponent != null) ? startComponent.getOffset() : 0;
|
||||
for (int currentRowIndex =
|
||||
rowIndex; currentRowIndex < numRowComponents; currentRowIndex++) {
|
||||
// Get the current data type at the index.
|
||||
DataTypeComponent comp = getComponent(currentRowIndex);
|
||||
DataType dt = comp.getDataType();
|
||||
int currentOffset = comp.getOffset();
|
||||
if (!dt.equals(DataType.DEFAULT)) {
|
||||
return currentOffset - previousOffset; // Ran into data type other than undefined byte.
|
||||
}
|
||||
}
|
||||
|
||||
return viewComposite.getLength() - previousOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the indicated row index is at or beyond the last component in this composite.
|
||||
*
|
||||
@ -1062,36 +1083,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not there are only undefined data types from the indicated rowIndex
|
||||
* until the end of the composite. There must be at least one undefined data type to return true.
|
||||
*
|
||||
* @param rowIndex the index of the row to begin checking for undefined data types.
|
||||
* @return true if an undefined data type is at the indicated row index and all components
|
||||
* from there to the end of the composite are undefined data types.
|
||||
*/
|
||||
protected boolean onlyUndefinedsUntilEnd(int rowIndex) {
|
||||
if (!isShowingUndefinedBytes()) {
|
||||
return false;
|
||||
}
|
||||
int numRowComponents = getNumComponents();
|
||||
if (rowIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
if (rowIndex >= numRowComponents) {
|
||||
return false; // Beyond last component.
|
||||
}
|
||||
for (int i = rowIndex; i < numRowComponents; i++) {
|
||||
// Get the current data type at the index.
|
||||
DataTypeComponent comp = getComponent(i);
|
||||
DataType dt = comp.getDataType();
|
||||
if (!dt.equals(DataType.DEFAULT)) {
|
||||
return false; // Ran into data type other than undefined byte.
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause the component at the specified index to consume undefined bytes
|
||||
* that follow it.
|
||||
@ -1670,16 +1661,17 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
if ((rowIndex < 0) || (rowIndex >= numRowComponents)) {
|
||||
return 0;
|
||||
}
|
||||
if (rowIndex + 1 == numRowComponents) {
|
||||
return Integer.MAX_VALUE; // On last component.
|
||||
DataTypeComponent dtc = getComponent(rowIndex);
|
||||
DataType dt = dtc.getDataType();
|
||||
int dtcLen = dt.getLength();
|
||||
if (dtcLen < 0) {
|
||||
dtcLen = dtc.getLength();
|
||||
}
|
||||
DataType dt = getComponent(rowIndex).getDataType();
|
||||
int maxDups = Integer.MAX_VALUE;
|
||||
// If editModel is showing undefined bytes (non-packed)
|
||||
// then constrain by number of undefined bytes that follow.
|
||||
if (isShowingUndefinedBytes() && (dt != DataType.DEFAULT)) {
|
||||
int numBytes = getNumUndefinedBytesAt(rowIndex + 1);
|
||||
maxDups = (numBytes / dt.getLength());
|
||||
int maxDups = (Integer.MAX_VALUE - getLength()) / dtcLen;
|
||||
if (dt != DataType.DEFAULT && isShowingUndefinedBytes() && !isAtEnd(rowIndex)) {
|
||||
// If editModel is showing undefined bytes (non-packed)
|
||||
// then constrain by number of undefined bytes that follow.
|
||||
maxDups = getNumUndefinedBytesAfter(dtc) / dtcLen;
|
||||
}
|
||||
return maxDups;
|
||||
}
|
||||
@ -1715,15 +1707,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return numBytesInRange / len;
|
||||
}
|
||||
// single line selected.
|
||||
|
||||
// If editModel is locked then constrain by number of undefined bytes that follow.
|
||||
if (!isShowingUndefinedBytes() || isAtEnd(rowIndex) ||
|
||||
onlyUndefinedsUntilEnd(rowIndex + 1)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
int numBytes = getNumUndefinedBytesAt(rowIndex + 1);
|
||||
return 1 + (numBytes / len);
|
||||
return getMaxDuplicates(rowIndex) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,8 +30,7 @@ import ghidra.util.HelpLocation;
|
||||
* <p>
|
||||
* Note: Any new actions must be registered in the editor manager via the actions's name.
|
||||
*/
|
||||
abstract public class CompositeEditorTableAction extends DockingAction
|
||||
implements CompositeEditorModelListener {
|
||||
abstract public class CompositeEditorTableAction extends DockingAction {
|
||||
|
||||
static final String MAIN_ACTION_GROUP = "0_MAIN_EDITOR_ACTION";
|
||||
static final String UNDOREDO_ACTION_GROUP = "1_UNDOREDO_EDITOR_ACTION";
|
||||
@ -79,14 +78,12 @@ abstract public class CompositeEditorTableAction extends DockingAction
|
||||
this.model = provider.getModel();
|
||||
this.plugin = provider.plugin;
|
||||
this.tool = plugin.getTool();
|
||||
model.addCompositeEditorModelListener(this);
|
||||
String helpAnchor = provider.getHelpName() + "_" + getHelpName();
|
||||
setHelpLocation(new HelpLocation(provider.getHelpTopic(), helpAnchor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
model.removeCompositeEditorModelListener(this);
|
||||
super.dispose();
|
||||
provider = null;
|
||||
model = null;
|
||||
@ -108,43 +105,4 @@ abstract public class CompositeEditorTableAction extends DockingAction
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectionChanged() {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
public void editStateChanged(int i) {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compositeEditStateChanged(int type) {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFieldEditing() {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentDataChanged() {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compositeInfoChanged() {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statusChanged(String message, boolean beep) {
|
||||
// we are an action; don't care about status messages
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showUndefinedStateChanged(boolean showUndefinedBytes) {
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1146,6 +1146,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
for (CompositeViewerModelListener listener : modelListeners) {
|
||||
listener.selectionChanged();
|
||||
}
|
||||
provider.contextChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -215,36 +215,8 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
|
||||
viewDTM.withTransaction("Set Size", () -> {
|
||||
int length = currentLength;
|
||||
Structure structure = (Structure) viewComposite;
|
||||
if (length > size) {
|
||||
int numComponents = structure.getNumComponents();
|
||||
|
||||
DataTypeComponent dtc = structure.getComponentContaining(size);
|
||||
int ordinal = dtc.getOrdinal();
|
||||
|
||||
// retain any zero-length components which have an offset equal the new size
|
||||
while (dtc.getOffset() == size && dtc.getLength() == 0 &&
|
||||
(ordinal + 1) < numComponents) {
|
||||
dtc = structure.getComponent(++ordinal);
|
||||
}
|
||||
|
||||
// remove trailing components outside of new size
|
||||
for (int index = numComponents - 1; index >= ordinal; index--) {
|
||||
structure.delete(index);
|
||||
int bitFieldResidualBytes = structure.getNumComponents() - index;
|
||||
for (int i = 0; i < bitFieldResidualBytes; i++) {
|
||||
// bitfield removal may cause injection of undefined bytes - remove them
|
||||
structure.delete(index);
|
||||
}
|
||||
}
|
||||
// structure may shrink too much from component removal - may need to grow
|
||||
length = (viewComposite.isZeroLength()) ? 0 : viewComposite.getLength();
|
||||
}
|
||||
if (length < size) {
|
||||
// Increasing structure length.
|
||||
structure.growStructure(size - length);
|
||||
}
|
||||
structure.setLength(size);
|
||||
});
|
||||
notifyCompositeChanged();
|
||||
}
|
||||
@ -372,13 +344,17 @@ class StructureEditorModel extends CompEditorModel {
|
||||
throw new IllegalArgumentException("Invalid component index specified");
|
||||
}
|
||||
DataType dt = originalComp.getDataType();
|
||||
int dtLen = dt.getLength();
|
||||
int len = dt.getLength();
|
||||
if (len < 0) {
|
||||
len = originalComp.getLength();
|
||||
}
|
||||
checkIsAllowableDataType(dt);
|
||||
|
||||
int dtcLen = len;
|
||||
viewDTM.withTransaction("Duplicate Components", () -> {
|
||||
int startIndex = index + 1;
|
||||
if (isShowingUndefinedBytes() && (dt != DataType.DEFAULT)) {
|
||||
int endIndex = startIndex + (dtLen * multiple) - 1;
|
||||
if (dt != DataType.DEFAULT && isShowingUndefinedBytes() && !isAtEnd(index)) {
|
||||
int endIndex = startIndex + (dtcLen * multiple) - 1;
|
||||
if (startIndex < getNumComponents()) {
|
||||
deleteComponentRange(startIndex, endIndex, monitor);
|
||||
}
|
||||
@ -605,21 +581,16 @@ class StructureEditorModel extends CompEditorModel {
|
||||
if (comp == null) {
|
||||
return false;
|
||||
}
|
||||
DataType dt = comp.getDataType();
|
||||
if (viewComposite.isPackingEnabled()) {
|
||||
if (viewComposite.isPackingEnabled() || isAtEnd(rowIndex)) {
|
||||
return true;
|
||||
}
|
||||
DataType dt = comp.getDataType();
|
||||
if (dt.equals(DataType.DEFAULT)) {
|
||||
return true; // Insert an undefined and push everything down.
|
||||
}
|
||||
if (comp.isBitFieldComponent()) {
|
||||
return false; // unable to place non-packed bitfield in a reasonable fashion
|
||||
}
|
||||
// Can always duplicate at the end.
|
||||
if (isAtEnd(rowIndex) || onlyUndefinedsUntilEnd(rowIndex + 1)) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise can only duplicate if enough room.
|
||||
|
||||
// Get the size of the data type at this index and the number of
|
||||
// undefined bytes following it.
|
||||
@ -627,8 +598,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||
if (dtSize <= 0) {
|
||||
dtSize = comp.getLength();
|
||||
}
|
||||
int undefSize = getNumUndefinedBytesAt(rowIndex + 1);
|
||||
if (dtSize <= undefSize) {
|
||||
if (dtSize <= getNumUndefinedBytesAfter(comp)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -701,8 +671,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||
1 == currentRange.getEnd().getIndex().intValue());
|
||||
|
||||
if (isOneComponent) {
|
||||
if (!isShowingUndefinedBytes() || isAtEnd(currentIndex) ||
|
||||
onlyUndefinedsUntilEnd(currentIndex + 1)) {
|
||||
if (isPackingEnabled() || isAtEnd(currentIndex)) {
|
||||
return true; // allow replace of component when aligning.
|
||||
}
|
||||
|
||||
@ -711,10 +680,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||
DataTypeComponent comp = getComponent(currentIndex);
|
||||
if (comp != null) {
|
||||
DataType compDt = comp.getDataType();
|
||||
int numCompBytes = comp.getLength();
|
||||
int numFollowing = getNumUndefinedBytesAt(currentIndex + 1);
|
||||
int numAvailable = numCompBytes + numFollowing;
|
||||
// Drop on pointer.
|
||||
if (compDt instanceof Pointer ||
|
||||
DataTypeHelper.getBaseType(compDt) instanceof Pointer) {
|
||||
// Don't create undefined byte pointers.
|
||||
@ -723,10 +688,8 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (datatype.getLength() <= numAvailable) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
int numAvailable = comp.getLength() + getNumUndefinedBytesAfter(comp);
|
||||
return datatype.getLength() <= numAvailable;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -774,17 +737,18 @@ class StructureEditorModel extends CompEditorModel {
|
||||
catch (InvalidDataTypeException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isShowingUndefinedBytes()) {
|
||||
if (isAtEnd(rowIndex)) {
|
||||
return true;
|
||||
}
|
||||
int maxBytes = dtc.getLength() + getNumUndefinedBytesAt(rowIndex + 1);
|
||||
if (dataType.getLength() > maxBytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isPackingEnabled() || isAtEnd(rowIndex)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
int undefSize = getNumUndefinedBytesAfter(dtc);
|
||||
if (undefSize < 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int numAvailable = dtc.getLength() + undefSize;
|
||||
return dataType.getLength() <= numAvailable;
|
||||
}
|
||||
|
||||
// *************************************************************
|
||||
@ -804,9 +768,11 @@ class StructureEditorModel extends CompEditorModel {
|
||||
*/
|
||||
@Override
|
||||
public int getMaxAddLength(int rowIndex) {
|
||||
int maxLength = Integer.MAX_VALUE;
|
||||
if (rowIndex >= getNumComponents() - 1) {
|
||||
return maxLength;
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (isPackingEnabled() || isAtEnd(rowIndex)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
DataTypeComponent comp = getComponent(rowIndex);
|
||||
FieldRange currentRange = getSelectedRangeContaining(rowIndex);
|
||||
@ -817,18 +783,9 @@ class StructureEditorModel extends CompEditorModel {
|
||||
1 == currentRange.getEnd().getIndex().intValue());
|
||||
|
||||
if (isOneComponent) {
|
||||
if (!isShowingUndefinedBytes()) {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
// FreeForm editing mode (showing Undefined Bytes).
|
||||
int numAvailable = comp.getLength() + getNumUndefinedBytesAt(rowIndex + 1);
|
||||
return (maxLength == -1) ? numAvailable : Math.min(maxLength, numAvailable);
|
||||
return comp.getLength() + getNumUndefinedBytesAfter(comp);
|
||||
}
|
||||
DataTypeComponent startComp = getComponent(currentRange.getStart().getIndex().intValue());
|
||||
DataTypeComponent endComp = getComponent(currentRange.getEnd().getIndex().intValue() - 1);
|
||||
int numAvailable = endComp.getOffset() + endComp.getLength() - startComp.getOffset();
|
||||
return (maxLength == -1) ? numAvailable : Math.min(maxLength, numAvailable);
|
||||
return getNumBytesInRange(currentRange);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -842,26 +799,34 @@ class StructureEditorModel extends CompEditorModel {
|
||||
*/
|
||||
@Override
|
||||
public int getMaxReplaceLength(int currentIndex) {
|
||||
if (!isShowingUndefinedBytes()) { // Can replace at any index
|
||||
|
||||
if (currentIndex >= getNumComponents() - 1) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (isPackingEnabled() || isAtEnd(currentIndex)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
// Can only replace with what fits unless at last component or empty last line.
|
||||
DataTypeComponent comp = getComponent(currentIndex);
|
||||
int numComponents = getNumComponents();
|
||||
if ((currentIndex >= (numComponents - 1)) && (currentIndex <= numComponents)) {
|
||||
return Integer.MAX_VALUE; // Last component or empty entry immediately after it.
|
||||
}
|
||||
else if (comp == null) {
|
||||
if (comp == null) {
|
||||
return 0; // No such component. Not at valid edit index.
|
||||
}
|
||||
|
||||
// Otherwise, get size of component and number of Undefined bytes after it.
|
||||
FieldRange range = getSelectedRangeContaining(currentIndex);
|
||||
if (range == null ||
|
||||
range.getStart().getIndex().intValue() == range.getEnd().getIndex().intValue() - 1) {
|
||||
return comp.getLength() + getNumUndefinedBytesAt(currentIndex + 1);
|
||||
FieldRange currentRange = getSelectedRangeContaining(currentIndex);
|
||||
boolean isOneComponent =
|
||||
(currentRange == null) || (currentRange.getStart().getIndex().intValue() +
|
||||
1 == currentRange.getEnd().getIndex().intValue());
|
||||
|
||||
if (isOneComponent) {
|
||||
return comp.getLength() + getNumUndefinedBytesAfter(comp);
|
||||
}
|
||||
return getNumBytesInRange(range);
|
||||
return getNumBytesInRange(currentRange);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -959,7 +924,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||
int componentOrdinal = convertRowToOrdinal(rowIndex);
|
||||
|
||||
// FreeForm editing mode (showing Undefined Bytes).
|
||||
if (isShowingUndefinedBytes() && !isAtEnd(rowIndex)) {
|
||||
if (!isPackingEnabled() && !isAtEnd(rowIndex)) {
|
||||
int origLen = getComponent(rowIndex).getLength();
|
||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||
return ((Structure) viewComposite).replace(componentOrdinal, dataType, length,
|
||||
@ -983,14 +948,22 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
else {
|
||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||
((Structure) viewComposite).delete(componentOrdinal);
|
||||
return ((Structure) viewComposite).insert(componentOrdinal, dataType, length,
|
||||
name, comment);
|
||||
Structure struct = (Structure) viewComposite;
|
||||
DataTypeComponent comp = getComponent(rowIndex);
|
||||
if (!isPackingEnabled()) {
|
||||
// We are at end with packing disabled - grow structure if needed
|
||||
int avail = comp.getLength() + getNumUndefinedBytesAfter(comp);
|
||||
if (length > avail) {
|
||||
struct.growStructure(length - avail);
|
||||
}
|
||||
}
|
||||
return ((Structure) viewComposite).replace(componentOrdinal, dataType, length, name, comment);
|
||||
});
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
catch (IllegalArgumentException exc) {
|
||||
// NOTE: Use of exception may cause transaction rollback
|
||||
throw new InvalidDataTypeException(exc.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -525,17 +525,6 @@ class UnionEditorModel extends CompEditorModel {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of undefined bytes that are available in the structure
|
||||
* beginning at the specified row index.
|
||||
*
|
||||
* @param rowIndex the index of the row
|
||||
*/
|
||||
@Override
|
||||
protected int getNumUndefinedBytesAt(int rowIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ?????
|
||||
*
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -393,6 +393,11 @@ public abstract class BiDirectionDataType extends StructureDataType
|
||||
notifySizeChanged();
|
||||
return dtc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(int len) {
|
||||
throw new UnsupportedOperationException("setLength not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the size of the bidirectional data type If amount is positive then the positive
|
||||
|
@ -278,7 +278,7 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
|
||||
@Override
|
||||
public void componentDataChanged() {
|
||||
// Don't need to update other than table when component data changes.
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -593,12 +593,12 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||
assertNotNull(asciiDt);
|
||||
addAtPoint(asciiDt, 2, 3);
|
||||
|
||||
assertEquals(3, structureModel.getNumComponents());
|
||||
assertEquals(4, structureModel.getRowCount());
|
||||
assertEquals(7, structureModel.getNumComponents());
|
||||
assertEquals(8, structureModel.getRowCount());
|
||||
checkRow(0, 0, 1, "db", new ByteDataType(), "", "");
|
||||
checkRow(1, 1, 4, "float", new FloatDataType(), "", "");
|
||||
checkRow(2, 5, 1, "char", asciiDt, "", "");
|
||||
assertLength(6);
|
||||
assertLength(10);
|
||||
assertActualAlignment(1);
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -196,7 +196,7 @@ public class StructureEditorLockedActions3Test extends AbstractStructureEditorTe
|
||||
assertEquals(9, getModel().getNumComponents());
|
||||
assertEquals("byte", getDataType(1).getName());
|
||||
assertEquals(getDataType(1), dt1);
|
||||
assertEquals("pointer doesn't fit.", getModel().getStatus());
|
||||
assertTrue(getModel().getStatus().contains("requires 1 additional"));
|
||||
assertEquals(1, getDataType(1).getLength());
|
||||
assertEquals(1, getModel().getComponent(1).getLength());
|
||||
assertEquals(DataType.DEFAULT, getDataType(2));
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -78,7 +78,7 @@ public class StructureEditorLockedDnDTest extends AbstractStructureEditorTest {
|
||||
assertTrue(getDataType(1).isEquivalent(dt1));
|
||||
assertEquals(dt1.getLength(), model.getComponent(1).getLength());
|
||||
assertEquals(325, model.getLength());
|
||||
assertEquals("double doesn't fit.", model.getStatus());
|
||||
assertTrue(model.getStatus().contains("requires 7 additional"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -119,14 +119,14 @@ public class StructureEditorUnlockedActions2Test
|
||||
checkSelection(new int[] { 0 });
|
||||
|
||||
invoke(action);
|
||||
assertEquals(1, model.getNumComponents());
|
||||
assertEquals(8, model.getNumComponents());
|
||||
assertTrue(getDataType(0).isEquivalent(new ByteDataType()));
|
||||
assertEquals(1, getLength(0));
|
||||
checkSelection(new int[] { 0 });
|
||||
|
||||
CycleGroupAction floatAction = getCycleGroup(new FloatDataType());
|
||||
invoke(floatAction);
|
||||
assertEquals(1, model.getNumComponents());
|
||||
assertEquals(5, model.getNumComponents());
|
||||
assertTrue(getDataType(0).isEquivalent(new FloatDataType()));
|
||||
assertEquals(4, getLength(0));
|
||||
checkSelection(new int[] { 0 });
|
||||
@ -138,7 +138,7 @@ public class StructureEditorUnlockedActions2Test
|
||||
checkSelection(new int[] { 0 });
|
||||
|
||||
invoke(floatAction);
|
||||
assertEquals(1, model.getNumComponents());
|
||||
assertEquals(5, model.getNumComponents());
|
||||
assertTrue(getDataType(0).isEquivalent(new FloatDataType()));
|
||||
assertEquals(4, getLength(0));
|
||||
checkSelection(new int[] { 0 });
|
||||
|
@ -412,7 +412,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor
|
||||
assertTrue(getDataType(2).isEquivalent(new WordDataType()));
|
||||
invoke(pointerAction);
|
||||
|
||||
assertEquals("pointer doesn't fit.", model.getStatus());
|
||||
assertTrue(model.getStatus().contains("requires 2 additional"));
|
||||
assertEquals(num, model.getNumComponents());
|
||||
assertEquals("word", getDataType(2).getDisplayName());
|
||||
assertTrue(getDataType(2).isEquivalent(new WordDataType()));
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -45,7 +45,7 @@ public class StructureEditorUnlockedDnD4Test extends AbstractStructureEditorTest
|
||||
addAtPoint(dt, 0, 3);
|
||||
assertEquals(num, model.getNumComponents());
|
||||
assertTrue(getDataType(0).isEquivalent(DataType.DEFAULT));
|
||||
assertEquals("word doesn't fit.", model.getStatus());
|
||||
assertTrue(model.getStatus().contains("requires 1 additional"));
|
||||
|
||||
dt = programDTM.getDataType("/char");
|
||||
assertNotNull(dt);
|
||||
@ -114,7 +114,7 @@ public class StructureEditorUnlockedDnD4Test extends AbstractStructureEditorTest
|
||||
|
||||
addAtPoint(dt, 5, 3);
|
||||
|
||||
assertEquals("qword doesn't fit.", model.getStatus());
|
||||
assertTrue(model.getStatus().contains("requires 4 additional"));
|
||||
assertEquals(num, model.getNumComponents());
|
||||
assertEquals("float", getDataType(5).getDisplayName());
|
||||
assertEquals(29, model.getLength());
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -1046,6 +1046,41 @@ public class StructureDataTypeTest extends AbstractGenericTest {
|
||||
assertEquals(10, comps[3].getOffset());
|
||||
assertEquals(7, comps[3].getOrdinal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLength() {
|
||||
|
||||
assertEquals(8, struct.getLength());
|
||||
assertEquals(4, struct.getNumComponents());
|
||||
assertEquals(4, struct.getNumDefinedComponents());
|
||||
|
||||
struct.setLength(20);
|
||||
assertEquals(20, struct.getLength());
|
||||
assertEquals(16, struct.getNumComponents());
|
||||
assertEquals(4, struct.getNumDefinedComponents());
|
||||
|
||||
// new length is offcut within 3rd component at offset 0x3 which should get cleared
|
||||
struct.setLength(4);
|
||||
assertEquals(4, struct.getLength());
|
||||
assertEquals(3, struct.getNumComponents());
|
||||
assertEquals(2, struct.getNumDefinedComponents());
|
||||
|
||||
// Maximum length supported by GUI editor is ~Integer.MAX_VALUE/10
|
||||
int len = Integer.MAX_VALUE / 10;
|
||||
struct.setLength(len);
|
||||
assertEquals(len, struct.getLength());
|
||||
assertEquals(len - 1, struct.getNumComponents());
|
||||
assertEquals(2, struct.getNumDefinedComponents());
|
||||
|
||||
len /= 2;
|
||||
struct.replaceAtOffset(len-2, WordDataType.dataType, -1, "x", null); // will be preserved below
|
||||
struct.replaceAtOffset(len+2, WordDataType.dataType, -1, "y", null); // will be cleared below
|
||||
struct.setLength(len);
|
||||
assertEquals(len, struct.getLength());
|
||||
assertEquals(len - 2, struct.getNumComponents());
|
||||
assertEquals(3, struct.getNumDefinedComponents());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMany() {
|
||||
|
@ -236,9 +236,57 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(int len) {
|
||||
if (len < 0) {
|
||||
throw new IllegalArgumentException("Invalid length: " + len);
|
||||
}
|
||||
if (len == structLength || isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (len < structLength) {
|
||||
// identify index of first defined-component to be removed
|
||||
int index = Collections.binarySearch(components, Integer.valueOf(len),
|
||||
OffsetComparator.INSTANCE);
|
||||
|
||||
if (index < 0) {
|
||||
index = -index - 1;
|
||||
}
|
||||
else {
|
||||
index = backupToFirstComponentContainingOffset(index, len);
|
||||
}
|
||||
int definedComponentCount = components.size();
|
||||
if (index >= 0 && index < definedComponentCount) {
|
||||
for (int i = index; i < definedComponentCount; i++) {
|
||||
doDelete(components.get(i));
|
||||
}
|
||||
components = components.subList(0, index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
numComponents += len - structLength;
|
||||
}
|
||||
structLength = len;
|
||||
repack(false, false);
|
||||
notifySizeChanged(false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void growStructure(int amount) {
|
||||
if (isPackingEnabled()) {
|
||||
if (amount < 0) {
|
||||
throw new IllegalArgumentException("Invalid growth amount: " + amount);
|
||||
}
|
||||
if (amount == 0 || isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
lock.acquire();
|
||||
|
@ -914,6 +914,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
||||
}
|
||||
}
|
||||
if (restored) {
|
||||
invalidateCache();
|
||||
notifyRestored();
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@ -430,13 +430,22 @@ public interface Structure extends Composite {
|
||||
String comment) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Increases the size of the structure by the specified amount by adding undefined filler at the
|
||||
* Increases the size of the structure by the specified positive amount by adding undefined filler at the
|
||||
* end of the structure. NOTE: This method only has an affect on non-packed structures.
|
||||
*
|
||||
* @param amount the amount by which to grow the structure.
|
||||
* @throws IllegalArgumentException if amount < 1
|
||||
* @throws IllegalArgumentException if amount < 0
|
||||
*/
|
||||
public void growStructure(int amount);
|
||||
|
||||
/**
|
||||
* Set the size of the structure to the specified byte-length. If the length is shortened defined
|
||||
* components will be cleared and removed as required.
|
||||
* NOTE: This method only has an affect on non-packed structures.
|
||||
* @param length new structure length
|
||||
* @throws IllegalArgumentException if length < 0
|
||||
*/
|
||||
public void setLength(int length);
|
||||
|
||||
/**
|
||||
* <code>BitOffsetComparator</code> provides ability to compare an normalized bit offset (see
|
||||
|
@ -624,9 +624,43 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||
return dtc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(int len) {
|
||||
if (len < 0) {
|
||||
throw new IllegalArgumentException("Invalid length: " + len);
|
||||
}
|
||||
if (len == structLength || isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (len < structLength) {
|
||||
// identify index of first defined-component to be removed
|
||||
int index = Collections.binarySearch(components, Integer.valueOf(len),
|
||||
OffsetComparator.INSTANCE);
|
||||
if (index < 0) {
|
||||
index = -index - 1;
|
||||
}
|
||||
else {
|
||||
index = backupToFirstComponentContainingOffset(index, len);
|
||||
}
|
||||
int definedComponentCount = components.size();
|
||||
if (index >= 0 && index < definedComponentCount) {
|
||||
components = components.subList(0, index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
numComponents += len - structLength;
|
||||
}
|
||||
structLength = len;
|
||||
repack(false);
|
||||
notifySizeChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void growStructure(int amount) {
|
||||
if (isPackingEnabled()) {
|
||||
if (amount < 0) {
|
||||
throw new IllegalArgumentException("Invalid growth amount: " + amount);
|
||||
}
|
||||
if (amount == 0 || isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
doGrowStructure(amount);
|
||||
|
@ -1449,6 +1449,40 @@ public class StructureDBTest extends AbstractGenericTest {
|
||||
assertEquals(dtc1, barStruct.getComponent(6));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLength() {
|
||||
|
||||
assertEquals(8, struct.getLength());
|
||||
assertEquals(4, struct.getNumComponents());
|
||||
assertEquals(4, struct.getNumDefinedComponents());
|
||||
|
||||
struct.setLength(20);
|
||||
assertEquals(20, struct.getLength());
|
||||
assertEquals(16, struct.getNumComponents());
|
||||
assertEquals(4, struct.getNumDefinedComponents());
|
||||
|
||||
// new length is offcut within 3rd component at offset 0x3 which should get cleared
|
||||
struct.setLength(4);
|
||||
assertEquals(4, struct.getLength());
|
||||
assertEquals(3, struct.getNumComponents());
|
||||
assertEquals(2, struct.getNumDefinedComponents());
|
||||
|
||||
// Maximum length supported by GUI editor is ~Integer.MAX_VALUE/10
|
||||
int len = Integer.MAX_VALUE / 10;
|
||||
struct.setLength(len);
|
||||
assertEquals(len, struct.getLength());
|
||||
assertEquals(len - 1, struct.getNumComponents());
|
||||
assertEquals(2, struct.getNumDefinedComponents());
|
||||
|
||||
len /= 2;
|
||||
struct.replaceAtOffset(len-2, WordDataType.dataType, -1, "x", null); // will be preserved below
|
||||
struct.replaceAtOffset(len+2, WordDataType.dataType, -1, "y", null); // will be cleared below
|
||||
struct.setLength(len);
|
||||
assertEquals(len, struct.getLength());
|
||||
assertEquals(len - 2, struct.getNumComponents());
|
||||
assertEquals(3, struct.getNumDefinedComponents());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMany() {
|
||||
|
Loading…
Reference in New Issue
Block a user