mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-5586 Refactored and fixed function stack frame editor
This commit is contained in:
parent
4a46edc9fe
commit
72a94daa1d
20 changed files with 1920 additions and 1949 deletions
|
@ -248,17 +248,17 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
|
// public DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
|
||||||
throws UsrException {
|
// throws UsrException {
|
||||||
dtString = DataTypeHelper.stripWhiteSpace(dtString);
|
// dtString = DataTypeHelper.stripWhiteSpace(dtString);
|
||||||
if ((dtString == null) || (dtString.length() < 1)) {
|
// if ((dtString == null) || (dtString.length() < 1)) {
|
||||||
if (rowIndex == getNumComponents()) {
|
// if (rowIndex == getNumComponents()) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return super.validateComponentDataType(rowIndex, dtString);
|
// return super.validateComponentDataType(rowIndex, dtString);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAddAllowed(DataType dataType) {
|
public boolean isAddAllowed(DataType dataType) {
|
||||||
|
@ -894,18 +894,18 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
protected abstract void replaceOriginalComponents();
|
protected abstract void replaceOriginalComponents();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkIsAllowableDataType(DataType datatype) throws InvalidDataTypeException {
|
protected void checkIsAllowableDataType(DataType dataType) throws InvalidDataTypeException {
|
||||||
|
|
||||||
super.checkIsAllowableDataType(datatype);
|
super.checkIsAllowableDataType(dataType);
|
||||||
|
|
||||||
// Verify that we aren't adding this structure or anything that it is
|
// Verify that we aren't adding this structure or anything that it is
|
||||||
// part of to this editable structure.
|
// part of to this editable structure.
|
||||||
if (datatype.equals(viewComposite)) {
|
if (dataType.equals(viewComposite)) {
|
||||||
String msg = "Data type \"" + datatype.getDisplayName() + "\" can't contain itself.";
|
String msg = "Data type \"" + dataType.getDisplayName() + "\" can't contain itself.";
|
||||||
throw new InvalidDataTypeException(msg);
|
throw new InvalidDataTypeException(msg);
|
||||||
}
|
}
|
||||||
else if (DataTypeUtilities.isSecondPartOfFirst(datatype, viewComposite)) {
|
else if (DataTypeUtilities.isSecondPartOfFirst(dataType, viewComposite)) {
|
||||||
String msg = "Data type \"" + datatype.getDisplayName() + "\" has \"" +
|
String msg = "Data type \"" + dataType.getDisplayName() + "\" has \"" +
|
||||||
viewComposite.getDisplayName() + "\" within it.";
|
viewComposite.getDisplayName() + "\" within it.";
|
||||||
throw new InvalidDataTypeException(msg);
|
throw new InvalidDataTypeException(msg);
|
||||||
}
|
}
|
||||||
|
@ -1314,25 +1314,25 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
|
DataType dataType = viewDTM.getDataType(path);
|
||||||
if (dataType == null) {
|
if (dataType == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!path.equals(originalDataTypePath)) {
|
if (!path.equals(originalDataTypePath)) {
|
||||||
DataType dt = viewDTM.getDataType(path);
|
if (!viewDTM.isViewDataTypeFromOriginalDTM(dataType)) {
|
||||||
if (dt != null) {
|
return;
|
||||||
if (hasSubDt(viewComposite, path)) {
|
|
||||||
String msg = "Removed sub-component data type \"" + path;
|
|
||||||
setStatus(msg, true);
|
|
||||||
}
|
|
||||||
viewDTM.withTransaction("Removed Dependency", () -> {
|
|
||||||
viewDTM.clearUndoOnChange();
|
|
||||||
viewDTM.remove(dt, TaskMonitor.DUMMY);
|
|
||||||
});
|
|
||||||
fireTableDataChanged();
|
|
||||||
componentDataChanged();
|
|
||||||
}
|
}
|
||||||
|
if (hasSubDt(viewComposite, path)) {
|
||||||
|
String msg = "Removed sub-component data type \"" + path;
|
||||||
|
setStatus(msg, true);
|
||||||
|
}
|
||||||
|
viewDTM.withTransaction("Removed Dependency", () -> {
|
||||||
|
viewDTM.clearUndoOnChange();
|
||||||
|
viewDTM.remove(dataType, TaskMonitor.DUMMY);
|
||||||
|
});
|
||||||
|
fireTableDataChanged();
|
||||||
|
componentDataChanged();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1366,56 +1366,7 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||||
|
dataTypeMoved(dtm, oldPath, newPath);
|
||||||
if (dtm != originalDTM) {
|
|
||||||
throw new AssertException("Listener only supports original DTM");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLoaded()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldPath.getDataTypeName().equals(newPath.getDataTypeName())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String newName = newPath.getDataTypeName();
|
|
||||||
String oldName = oldPath.getDataTypeName();
|
|
||||||
|
|
||||||
// Does the old name match our original name.
|
|
||||||
// Check originalCompositeId to ensure original type is managed
|
|
||||||
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
|
|
||||||
oldPath.equals(originalDataTypePath)) {
|
|
||||||
originalDataTypePath = newPath;
|
|
||||||
try {
|
|
||||||
if (viewComposite.getName().equals(oldName)) {
|
|
||||||
setName(newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (InvalidNameException | DuplicateNameException e) {
|
|
||||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for managed datatype changing
|
|
||||||
DataType dt = viewDTM.getDataType(oldPath);
|
|
||||||
if (dt == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
viewDTM.withTransaction("Renamed Dependency", () -> {
|
|
||||||
viewDTM.clearUndoOnChange();
|
|
||||||
try {
|
|
||||||
dt.setName(newPath.getDataTypeName());
|
|
||||||
}
|
|
||||||
catch (InvalidNameException | DuplicateNameException e) {
|
|
||||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fireTableDataChanged();
|
|
||||||
componentDataChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1429,31 +1380,64 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dt = viewDTM.getDataType(oldPath);
|
if (oldPath.equals(newPath)) {
|
||||||
if (dt == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
String newName = newPath.getDataTypeName();
|
||||||
viewDTM.withTransaction("Moved " + oldPath, () -> {
|
String oldName = oldPath.getDataTypeName();
|
||||||
viewDTM.clearUndoOnChange();
|
|
||||||
Category newDtCat = viewDTM.createCategory(newPath.getCategoryPath());
|
|
||||||
newDtCat.moveDataType(dt, null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (DataTypeDependencyException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (originalDataTypePath.getDataTypeName().equals(newPath.getDataTypeName()) &&
|
CategoryPath newCategoryPath = newPath.getCategoryPath();
|
||||||
originalDataTypePath.getCategoryPath().equals(oldPath.getCategoryPath())) {
|
CategoryPath oldCategoryPath = oldPath.getCategoryPath();
|
||||||
originalDataTypePath = newPath;
|
|
||||||
|
// Does the old name match our original name.
|
||||||
|
// Check originalCompositeId to ensure original type is managed
|
||||||
|
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
|
||||||
|
oldPath.equals(originalDataTypePath)) {
|
||||||
|
|
||||||
|
viewDTM.withTransaction("Name Changed", () -> {
|
||||||
|
viewDTM.clearUndoOnChange();
|
||||||
|
originalDataTypePath = newPath;
|
||||||
|
try {
|
||||||
|
if (viewComposite.getName().equals(oldName)) {
|
||||||
|
setName(newName);
|
||||||
|
}
|
||||||
|
if (!newCategoryPath.equals(oldCategoryPath)) {
|
||||||
|
viewComposite.setCategoryPath(newCategoryPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidNameException | DuplicateNameException e) {
|
||||||
|
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
compositeInfoChanged();
|
compositeInfoChanged();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fireTableDataChanged();
|
// Check for managed datatype changing
|
||||||
componentDataChanged();
|
DataType originalDt = originalDTM.getDataType(newPath);
|
||||||
|
if (!(originalDt instanceof DatabaseObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DataType dt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(originalDt));
|
||||||
|
if (dt == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
viewDTM.withTransaction("Renamed Dependency", () -> {
|
||||||
|
viewDTM.clearUndoOnChange();
|
||||||
|
try {
|
||||||
|
dt.setName(newName);
|
||||||
|
if (!newCategoryPath.equals(oldCategoryPath)) {
|
||||||
|
dt.setCategoryPath(newCategoryPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidNameException | DuplicateNameException e) {
|
||||||
|
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fireTableDataChanged();
|
||||||
|
componentDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1517,11 +1501,10 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
// potentially many types getting changed by one change.
|
// potentially many types getting changed by one change.
|
||||||
DataType changedDt = originalDTM.getDataType(path);
|
DataType changedDt = originalDTM.getDataType(path);
|
||||||
if (!(changedDt instanceof DatabaseObject)) {
|
if (!(changedDt instanceof DatabaseObject)) {
|
||||||
// NOTE: viewDTM only maps view-to-original IDs for DataTypeDB
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long originalId = originalDTM.getID(changedDt);
|
DataType viewDt =
|
||||||
DataType viewDt = viewDTM.findMyDataTypeFromOriginalID(originalId);
|
viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(changedDt));
|
||||||
if (viewDt == null) {
|
if (viewDt == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1562,30 +1545,32 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||||
if (!oldPath.equals(originalDataTypePath)) {
|
if (!oldPath.equals(originalDataTypePath)) {
|
||||||
// Check for type which may be referenced by viewComposite
|
// Check for type which may be referenced by viewComposite
|
||||||
DataType dt = viewDTM.getDataType(oldPath);
|
DataType dt = viewDTM.getDataType(oldPath);
|
||||||
if (dt != null) {
|
if (dt == null || !viewDTM.isViewDataTypeFromOriginalDTM(dt)) {
|
||||||
if (hasSubDt(viewComposite, oldPath)) {
|
return;
|
||||||
String msg = "Replaced data type \"" + oldPath +
|
|
||||||
"\", which is a sub-component of \"" + getOriginalDataTypeName() + "\".";
|
|
||||||
setStatus(msg, true);
|
|
||||||
}
|
|
||||||
// NOTE: depending upon event sequence and handling a
|
|
||||||
// re-load may have occurred and replacement may be unnecessary
|
|
||||||
try {
|
|
||||||
viewDTM.withTransaction("Replaced Dependency", () -> {
|
|
||||||
viewDTM.clearUndoOnChange();
|
|
||||||
viewDTM.replaceDataType(dt, newDataType, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (DataTypeDependencyException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear undo/redo stack to avoid inconsistency with originalDTM
|
|
||||||
viewDTM.clearUndo();
|
|
||||||
|
|
||||||
fireTableDataChanged();
|
|
||||||
componentDataChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasSubDt(viewComposite, oldPath)) {
|
||||||
|
String msg = "Replaced data type \"" + oldPath +
|
||||||
|
"\", which is a sub-component of \"" + getOriginalDataTypeName() + "\".";
|
||||||
|
setStatus(msg, true);
|
||||||
|
}
|
||||||
|
// NOTE: depending upon event sequence and handling a
|
||||||
|
// re-load may have occurred and replacement may be unnecessary
|
||||||
|
try {
|
||||||
|
viewDTM.withTransaction("Replaced Dependency", () -> {
|
||||||
|
viewDTM.clearUndoOnChange();
|
||||||
|
viewDTM.replaceDataType(dt, newDataType, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (DataTypeDependencyException e) {
|
||||||
|
throw new AssertException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear undo/redo stack to avoid inconsistency with originalDTM
|
||||||
|
viewDTM.clearUndo();
|
||||||
|
|
||||||
|
fireTableDataChanged();
|
||||||
|
componentDataChanged();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
originalDataTypePath = originalComposite.getDataTypePath();
|
originalDataTypePath = originalComposite.getDataTypePath();
|
||||||
currentName = dataType.getName();
|
currentName = dataType.getName();
|
||||||
|
|
||||||
createViewCompositeFromOriginalComposite(originalComposite);
|
createViewCompositeFromOriginalComposite();
|
||||||
|
|
||||||
// Listen so we can update editor if name changes for this structure.
|
// Listen so we can update editor if name changes for this structure.
|
||||||
originalDTM.addDataTypeManagerListener(this);
|
originalDTM.addDataTypeManagerListener(this);
|
||||||
|
@ -204,12 +204,10 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create {@code viewComposite} and associated view datatype manager ({@code viewDTM}) and
|
* Create {@code viewComposite} and {@link CompositeViewerDataTypeManager viewDTM} for this
|
||||||
* changes listener(s) if required.
|
* editor and the {@code originalComposite}.
|
||||||
*
|
|
||||||
* @param original original composite being loaded
|
|
||||||
*/
|
*/
|
||||||
protected void createViewCompositeFromOriginalComposite(T original) {
|
protected void createViewCompositeFromOriginalComposite() {
|
||||||
|
|
||||||
if (viewDTM != null) {
|
if (viewDTM != null) {
|
||||||
viewDTM.close();
|
viewDTM.close();
|
||||||
|
@ -217,8 +215,9 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use temporary standalone view datatype manager
|
// Use temporary standalone view datatype manager
|
||||||
viewDTM = new CompositeViewerDataTypeManager<>(original.getDataTypeManager().getName(),
|
viewDTM =
|
||||||
original, this::componentEdited, this::restoreEditor);
|
new CompositeViewerDataTypeManager<>(originalComposite.getDataTypeManager().getName(),
|
||||||
|
originalComposite, this::componentEdited, this::restoreEditor);
|
||||||
|
|
||||||
viewComposite = viewDTM.getResolvedViewComposite();
|
viewComposite = viewDTM.getResolvedViewComposite();
|
||||||
|
|
||||||
|
@ -230,7 +229,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
// underlying datatype default setting value being presented when adjusting component
|
// underlying datatype default setting value being presented when adjusting component
|
||||||
// default settings.
|
// default settings.
|
||||||
viewDTM.withTransaction("Load Settings",
|
viewDTM.withTransaction("Load Settings",
|
||||||
() -> cloneAllComponentSettings(original, viewComposite));
|
() -> cloneAllComponentSettings(originalComposite, viewComposite));
|
||||||
viewDTM.clearUndo();
|
viewDTM.clearUndo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +316,6 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
throw new InvalidDataTypeException("Data types of size 0 are not allowed.");
|
throw new InvalidDataTypeException("Data types of size 0 are not allowed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Need to handle proper placement for big-endian within a larger component (i.e., right-justified)
|
|
||||||
return DataTypeInstance.getDataTypeInstance(resultDt, resultLen,
|
return DataTypeInstance.getDataTypeInstance(resultDt, resultLen,
|
||||||
viewComposite.isPackingEnabled());
|
viewComposite.isPackingEnabled());
|
||||||
}
|
}
|
||||||
|
@ -481,13 +479,13 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
dtName = previousDt.getDisplayName();
|
dtName = previousDt.getDisplayName();
|
||||||
}
|
}
|
||||||
DataType newDt = null;
|
DataType newDt = null;
|
||||||
int newLength = -1;
|
int newLength;
|
||||||
if (dataTypeObject instanceof DataTypeInstance dti) {
|
if (dataTypeObject instanceof DataTypeInstance dti) {
|
||||||
newDt = resolve(dti.getDataType());
|
newDt = dti.getDataType();
|
||||||
newLength = dti.getLength();
|
newLength = dti.getLength();
|
||||||
}
|
}
|
||||||
else if (dataTypeObject instanceof DataType dt) {
|
else if (dataTypeObject instanceof DataType dt) {
|
||||||
newDt = resolve(dt);
|
newDt = dt;
|
||||||
newLength = newDt.getLength();
|
newLength = newDt.getLength();
|
||||||
}
|
}
|
||||||
else if (dataTypeObject instanceof String dtString) {
|
else if (dataTypeObject instanceof String dtString) {
|
||||||
|
@ -506,6 +504,9 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
newLength = 0;
|
newLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataType dataType = newDt.clone(originalDTM);
|
||||||
|
newLength = newDt.getLength();
|
||||||
|
|
||||||
checkIsAllowableDataType(newDt);
|
checkIsAllowableDataType(newDt);
|
||||||
|
|
||||||
if (newLength < 0) {
|
if (newLength < 0) {
|
||||||
|
@ -535,8 +536,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set component datatype and length on view composite
|
// Set component datatype and length on view composite
|
||||||
DataType dataType = resolve(newDt); // probably already resolved
|
setComponentDataTypeInstance(rowIndex, newDt, newLength);
|
||||||
setComponentDataTypeInstance(rowIndex, dataType, newLength);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1434,51 +1434,51 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||||
* @return a valid data type instance or null if at blank line with no data type name.
|
* @return a valid data type instance or null if at blank line with no data type name.
|
||||||
* @throws UsrException indicating that the data type is not valid.
|
* @throws UsrException indicating that the data type is not valid.
|
||||||
*/
|
*/
|
||||||
protected DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
|
// protected DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
|
||||||
throws UsrException {
|
// throws UsrException {
|
||||||
DataType dt = null;
|
// DataType dt = null;
|
||||||
String dtName = "";
|
// String dtName = "";
|
||||||
dtString = DataTypeHelper.stripWhiteSpace(dtString);
|
// dtString = DataTypeHelper.stripWhiteSpace(dtString);
|
||||||
DataTypeComponent element = getComponent(rowIndex);
|
// DataTypeComponent element = getComponent(rowIndex);
|
||||||
if (element != null) {
|
// if (element != null) {
|
||||||
dt = element.getDataType();
|
// dt = element.getDataType();
|
||||||
dtName = dt.getDisplayName();
|
// dtName = dt.getDisplayName();
|
||||||
if (dtString.equals(dtName)) {
|
// if (dtString.equals(dtName)) {
|
||||||
return DataTypeInstance.getDataTypeInstance(element.getDataType(),
|
// return DataTypeInstance.getDataTypeInstance(element.getDataType(),
|
||||||
element.getLength(), usesAlignedLengthComponents());
|
// element.getLength(), usesAlignedLengthComponents());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
int newLength = 0;
|
// int newLength = 0;
|
||||||
DataType newDt = DataTypeHelper.parseDataType(rowIndex, dtString, this, originalDTM,
|
// DataType newDt = DataTypeHelper.parseDataType(rowIndex, dtString, this, originalDTM,
|
||||||
provider.dtmService);
|
// provider.dtmService);
|
||||||
if (newDt == null) {
|
// if (newDt == null) {
|
||||||
if (dt != null) {
|
// if (dt != null) {
|
||||||
throw new UsrException("No data type was specified.");
|
// throw new UsrException("No data type was specified.");
|
||||||
}
|
// }
|
||||||
throw new AssertException("Can't set data type to null.");
|
// throw new AssertException("Can't set data type to null.");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
checkIsAllowableDataType(newDt);
|
// checkIsAllowableDataType(newDt);
|
||||||
|
//
|
||||||
newLength = newDt.getLength();
|
// newLength = newDt.getLength();
|
||||||
if (newLength < 0) {
|
// if (newLength < 0) {
|
||||||
DataTypeInstance sizedDataType = DataTypeHelper.getSizedDataType(provider, newDt,
|
// DataTypeInstance sizedDataType = DataTypeHelper.getSizedDataType(provider, newDt,
|
||||||
lastNumBytes, getMaxReplaceLength(rowIndex));
|
// lastNumBytes, getMaxReplaceLength(rowIndex));
|
||||||
newLength = sizedDataType.getLength();
|
// newLength = sizedDataType.getLength();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
newDt = viewDTM.resolve(newDt, null);
|
// newDt = viewDTM.resolve(newDt, null);
|
||||||
int maxLength = getMaxReplaceLength(rowIndex);
|
// int maxLength = getMaxReplaceLength(rowIndex);
|
||||||
if (newLength <= 0) {
|
// if (newLength <= 0) {
|
||||||
throw new UsrException("Can't currently add this data type.");
|
// throw new UsrException("Can't currently add this data type.");
|
||||||
}
|
// }
|
||||||
if (maxLength > 0 && newLength > maxLength) {
|
// if (maxLength > 0 && newLength > maxLength) {
|
||||||
throw new UsrException(newDt.getDisplayName() + " doesn't fit.");
|
// throw new UsrException(newDt.getDisplayName() + " doesn't fit.");
|
||||||
}
|
// }
|
||||||
return DataTypeInstance.getDataTypeInstance(newDt, newLength,
|
// return DataTypeInstance.getDataTypeInstance(newDt, newLength,
|
||||||
usesAlignedLengthComponents());
|
// usesAlignedLengthComponents());
|
||||||
}
|
// }
|
||||||
|
|
||||||
@SuppressWarnings("unused") // the exception is thrown by subclasses
|
@SuppressWarnings("unused") // the exception is thrown by subclasses
|
||||||
protected void validateComponentName(int rowIndex, String name) throws UsrException {
|
protected void validateComponentName(int rowIndex, String name) throws UsrException {
|
||||||
|
|
|
@ -47,8 +47,7 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||||
* @param <M> Specific {@link CompositeEditorModel} implementation which supports editing T
|
* @param <M> Specific {@link CompositeEditorModel} implementation which supports editing T
|
||||||
*/
|
*/
|
||||||
public abstract class CompositeEditorProvider<T extends Composite, M extends CompositeEditorModel<T>>
|
public abstract class CompositeEditorProvider<T extends Composite, M extends CompositeEditorModel<T>>
|
||||||
extends ComponentProviderAdapter
|
extends ComponentProviderAdapter implements EditorProvider, EditorActionListener {
|
||||||
implements EditorProvider, EditorActionListener {
|
|
||||||
|
|
||||||
protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider");
|
protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider");
|
||||||
|
|
||||||
|
@ -317,7 +316,7 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
|
||||||
// Check for changes and prompt user to check if saving them.
|
// Check for changes and prompt user to check if saving them.
|
||||||
if (editorModel.isValidName() && editorModel.hasChanges()) {
|
if (editorModel.isValidName() && editorModel.hasChanges()) {
|
||||||
String question = "The " + editorModel.getTypeName() + " Editor is closing.\n" +
|
String question = "The " + editorModel.getTypeName() + " Editor is closing.\n" +
|
||||||
"Save the changes to " + getDtPath() + "?";
|
"Save the changes to " + getDisplayName() + "?";
|
||||||
String title = "Save " + editorModel.getTypeName() + " Editor Changes?";
|
String title = "Save " + editorModel.getTypeName() + " Editor Changes?";
|
||||||
int response;
|
int response;
|
||||||
if (allowCancel) {
|
if (allowCancel) {
|
||||||
|
@ -337,6 +336,10 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getDisplayName() {
|
||||||
|
return getDtPath().toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWindowSubMenuName() {
|
public String getWindowSubMenuName() {
|
||||||
return getName();
|
return getName();
|
||||||
|
|
|
@ -19,6 +19,8 @@ import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import javax.help.UnsupportedOperationException;
|
||||||
|
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
import ghidra.program.database.DatabaseObject;
|
import ghidra.program.database.DatabaseObject;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -66,16 +68,15 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
private TreeSet<Long> orphanIds = new TreeSet<>();
|
private TreeSet<Long> orphanIds = new TreeSet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a data type manager that the structure editor will use internally for managing
|
* Creates a data type manager that the composite editor will use internally for managing
|
||||||
* dependencies for an unmanaged structure being edited. A single transaction will be started
|
* dependencies without resolving the actual composite being edited. A single transaction
|
||||||
* with this instantiation and held open until this instance is closed. Undo/redo is
|
* will be started with this instantiation and held open until this instance is closed.
|
||||||
* not be supported.
|
* Undo/redo and datatype pruning is not be supported.
|
||||||
* @param rootName the root name for this data type manager (usually the program name).
|
* @param rootName the root name for this data type manager (usually the program name).
|
||||||
* @param originalDTM the original data type manager.
|
* @param originalDTM the original data type manager.
|
||||||
*/
|
*/
|
||||||
public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
|
public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
|
||||||
this(rootName, originalDTM, null, null, null);
|
this(rootName, originalDTM, null, null, null);
|
||||||
clearUndo();
|
|
||||||
transactionId = startTransaction("Composite Edit");
|
transactionId = startTransaction("Composite Edit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +124,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private T resolveViewComposite() {
|
private T resolveViewComposite() {
|
||||||
return originalComposite != null ? (T) super.resolve(originalComposite, null)
|
return originalComposite != null ? (T) super.resolve(originalComposite, null) : null;
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeArchitecture() {
|
private void initializeArchitecture() {
|
||||||
|
@ -158,12 +158,18 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
if (!isUndoRedoAllowed()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
dataTypeIDMap.invalidate();
|
dataTypeIDMap.invalidate();
|
||||||
super.undo();
|
super.undo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void redo() {
|
public void redo() {
|
||||||
|
if (!isUndoRedoAllowed()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
dataTypeIDMap.invalidate();
|
dataTypeIDMap.invalidate();
|
||||||
super.redo();
|
super.redo();
|
||||||
}
|
}
|
||||||
|
@ -237,10 +243,12 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
public DataType replaceDataType(DataType existingViewDt, DataType replacementDt,
|
public DataType replaceDataType(DataType existingViewDt, DataType replacementDt,
|
||||||
boolean updateCategoryPath) throws DataTypeDependencyException {
|
boolean updateCategoryPath) throws DataTypeDependencyException {
|
||||||
|
|
||||||
long viewDtId = getID(existingViewDt);
|
if (existingViewDt.getDataTypeManager() != this) {
|
||||||
|
throw new IllegalArgumentException("datatype is not from this manager");
|
||||||
|
}
|
||||||
|
|
||||||
if (existingViewDt instanceof DatabaseObject) {
|
if (existingViewDt instanceof DatabaseObject) {
|
||||||
dataTypeIDMap.remove(viewDtId);
|
dataTypeIDMap.remove(getID(existingViewDt));
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType newResolvedDt =
|
DataType newResolvedDt =
|
||||||
|
@ -259,10 +267,12 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(DataType existingViewDt, TaskMonitor monitor) {
|
public boolean remove(DataType existingViewDt, TaskMonitor monitor) {
|
||||||
|
|
||||||
long viewDtId = getID(existingViewDt);
|
if (existingViewDt.getDataTypeManager() != this) {
|
||||||
|
throw new IllegalArgumentException("datatype is not from this manager");
|
||||||
|
}
|
||||||
|
|
||||||
if (existingViewDt instanceof DatabaseObject) {
|
if (existingViewDt instanceof DatabaseObject) {
|
||||||
dataTypeIDMap.remove(viewDtId);
|
dataTypeIDMap.remove(getID(existingViewDt));
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.remove(existingViewDt, monitor);
|
return super.remove(existingViewDt, monitor);
|
||||||
|
@ -373,7 +383,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
if (committed && dataTypeChanged && changeCallback != null) {
|
if (committed && dataTypeChanged && changeCallback != null) {
|
||||||
Swing.runLater(() -> changeCallback.call());
|
Swing.runLater(() -> changeCallback.call());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getTransactionCount() == 0) {
|
if (getTransactionCount() == 0) {
|
||||||
dataTypeChanged = false;
|
dataTypeChanged = false;
|
||||||
}
|
}
|
||||||
|
@ -432,14 +442,53 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataType findOriginalDataTypeFromMyID(long myId) {
|
/**
|
||||||
Long originalId = dataTypeIDMap.getOriginalIDFromViewID(myId);
|
* Find a resolved DB-datatype within this manager based upon its source datatype's ID
|
||||||
return originalId != null ? originalDTM.getDataType(originalId) : null;
|
* within the original datatype manager associated with this manager. This method is
|
||||||
}
|
* useful when attempting to matchup a datatype within this manager to one which has changed
|
||||||
|
* within the original datatype manager.
|
||||||
|
*
|
||||||
|
* @param originalId datatype ID within original datatype manager
|
||||||
|
* @return matching DB-datatype or null if not found
|
||||||
|
*/
|
||||||
public DataType findMyDataTypeFromOriginalID(long originalId) {
|
public DataType findMyDataTypeFromOriginalID(long originalId) {
|
||||||
Long myId = dataTypeIDMap.getViewIDFromOriginalID(originalId);
|
Long myId = dataTypeIDMap.getViewIDFromOriginalID(originalId);
|
||||||
return myId != null ? getDataType(myId) : null;
|
return myId != null ? getDataType(myId) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a resolved DB-datatype within the original datatype manager based upon a resolved
|
||||||
|
* datatype's ID within this manager. This method is useful when attempting to matchup a
|
||||||
|
* datatype within this manager to one which has possibly changed within the original
|
||||||
|
* datatype manager.
|
||||||
|
*
|
||||||
|
* @param myId resolved datatype ID within this datatype manager
|
||||||
|
* @return matching DB-datatype or null if not found
|
||||||
|
*/
|
||||||
|
public DataType findOriginalDataTypeFromMyID(long myId) {
|
||||||
|
Long originalId = dataTypeIDMap.getOriginalIDFromViewID(myId);
|
||||||
|
return originalId != null ? originalDTM.getDataType(originalId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the specified datatype which has previsouly been resolved to this datatype
|
||||||
|
* manager originated from original composite's source (e.g., program).
|
||||||
|
* <P>
|
||||||
|
* NOTE: Non-DB datatypes will always return false.
|
||||||
|
*
|
||||||
|
* @param existingViewDt existing datatype which has previously been resolved to this
|
||||||
|
* datatype manager.
|
||||||
|
* @return true if specified datatype originated from this manager's associated original
|
||||||
|
* datatype manager.
|
||||||
|
*/
|
||||||
|
public boolean isViewDataTypeFromOriginalDTM(DataType existingViewDt) {
|
||||||
|
if (existingViewDt.getDataTypeManager() != this) {
|
||||||
|
throw new IllegalArgumentException("datatype is not from this manager");
|
||||||
|
}
|
||||||
|
if (!(existingViewDt instanceof DatabaseObject)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return dataTypeIDMap.getOriginalIDFromViewID(getID(existingViewDt)) != null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,35 +199,35 @@ abstract class CompositeViewerModel<T extends Composite> extends AbstractTableMo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Resolves the data type against the indicated data type manager using the specified
|
// * Resolves the data type against the indicated data type manager using the specified
|
||||||
* conflictHandler. In general, a transaction should have already been initiated prior to
|
// * conflictHandler. In general, a transaction should have already been initiated prior to
|
||||||
* calling this method so that the true nature of the transaction may be established for
|
// * calling this method so that the true nature of the transaction may be established for
|
||||||
* use with undo/redo (e.g., Set Datatype).
|
// * use with undo/redo (e.g., Set Datatype).
|
||||||
*
|
// *
|
||||||
* @param dataType the data type to be resolved
|
// * @param dataType the data type to be resolved
|
||||||
* @param resolveDtm the data type manager to resolve the data type against
|
// * @param resolveDtm the data type manager to resolve the data type against
|
||||||
* @param conflictHandler the handler to be used for any conflicts encountered while resolving
|
// * @param conflictHandler the handler to be used for any conflicts encountered while resolving
|
||||||
* @return the resolved data type
|
// * @return the resolved data type
|
||||||
*/
|
// */
|
||||||
protected final DataType resolveDataType(DataType dataType, DataTypeManager resolveDtm,
|
// protected final DataType resolveDataType(DataType dataType, DataTypeManager resolveDtm,
|
||||||
DataTypeConflictHandler conflictHandler) {
|
// DataTypeConflictHandler conflictHandler) {
|
||||||
if (resolveDtm == null || dataType == DataType.DEFAULT) {
|
// if (resolveDtm == null || dataType == DataType.DEFAULT) {
|
||||||
return DataType.DEFAULT;
|
// return DataType.DEFAULT;
|
||||||
}
|
// }
|
||||||
return resolveDtm.withTransaction("Resolve " + dataType.getPathName(), () -> {
|
// return resolveDtm.withTransaction("Resolve " + dataType.getPathName(), () -> {
|
||||||
return resolveDtm.resolve(dataType, conflictHandler);
|
// return resolveDtm.resolve(dataType, conflictHandler);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Resolves the indicated data type against the working copy in the viewer's data type manager.
|
// * Resolves the indicated data type against the working copy in the viewer's data type manager.
|
||||||
* @param dataType the data type
|
// * @param dataType the data type
|
||||||
* @return the working copy of the data type.
|
// * @return the working copy of the data type.
|
||||||
*/
|
// */
|
||||||
public DataType resolve(DataType dataType) {
|
// public DataType resolve(DataType dataType) {
|
||||||
return resolveDataType(dataType, viewDTM, null);
|
// return resolveDataType(dataType, viewDTM, null);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current row
|
* Gets the current row
|
||||||
|
|
|
@ -1,726 +0,0 @@
|
||||||
/* ###
|
|
||||||
* 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.stackeditor;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.help.UnsupportedOperationException;
|
|
||||||
|
|
||||||
import ghidra.program.model.data.*;
|
|
||||||
import ghidra.util.exception.AssertException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link BiDirectionDataType} is a special structure data type that allows both positive and
|
|
||||||
* negative offset values.
|
|
||||||
* <P>
|
|
||||||
* NOTE: This special purpose datatype does not support resolving with a {@link DataTypeManager}
|
|
||||||
*/
|
|
||||||
public abstract class BiDirectionDataType extends StructureDataType
|
|
||||||
implements BiDirectionStructure {
|
|
||||||
|
|
||||||
protected static Comparator<Object> ordinalComparator = new OrdinalComparator();
|
|
||||||
protected static Comparator<Object> offsetComparator = new OffsetComparator();
|
|
||||||
protected int negativeLength;
|
|
||||||
protected int positiveLength;
|
|
||||||
protected int splitOffset; // division offset between negative/positive halves
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct {@link BiDirectionDataType}
|
|
||||||
* @param name data type display name
|
|
||||||
* @param negativeLength negative allocation size
|
|
||||||
* @param positiveLength positive allocation size
|
|
||||||
* @param splitOffset division offset between negative/positive halves
|
|
||||||
* @param dtm associated datatype manager for component datatypes
|
|
||||||
*/
|
|
||||||
protected BiDirectionDataType(String name, int negativeLength, int positiveLength,
|
|
||||||
int splitOffset, DataTypeManager dtm) {
|
|
||||||
super(CategoryPath.ROOT, name, negativeLength + positiveLength, dtm);
|
|
||||||
this.negativeLength = negativeLength;
|
|
||||||
this.positiveLength = positiveLength;
|
|
||||||
this.splitOffset = splitOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DataType validateDataType(DataType dataType) {
|
|
||||||
if (DataTypeComponent.usesZeroLengthComponent(dataType)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Zero-length datatype not permitted: " + dataType.getName());
|
|
||||||
}
|
|
||||||
if (dataType instanceof BitFieldDataType) {
|
|
||||||
throw new IllegalArgumentException("Bitfield not permitted: " + dataType.getName());
|
|
||||||
}
|
|
||||||
return super.validateDataType(dataType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getAlignment() {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"BiDirectionDataType.getAlignment() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean repack(boolean notify) {
|
|
||||||
throw new AssertException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setToDefaultAligned() {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setToMachineAligned() {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPackingEnabled(boolean aligned) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExplicitPackingValue(int packingValue) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setExplicitMinimumAlignment(int minimumAlignment) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DataTypeComponent getDefinedComponentAt(int offset) {
|
|
||||||
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
|
|
||||||
if (index >= 0) {
|
|
||||||
return components.get(index);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent getComponentAt(int offset) {
|
|
||||||
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
|
|
||||||
if (index >= 0) {
|
|
||||||
return components.get(index);
|
|
||||||
}
|
|
||||||
int ordinal = 0;
|
|
||||||
index = -index - 1;
|
|
||||||
int prevIndex = index - 1;
|
|
||||||
if (prevIndex < 0) {
|
|
||||||
ordinal = offset + negativeLength - splitOffset;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DataTypeComponent prevComp = components.get(prevIndex);
|
|
||||||
int prevOrdinal = prevComp.getOrdinal();
|
|
||||||
int prevOffset = prevComp.getOffset();
|
|
||||||
int endOffset = prevComp.getEndOffset();
|
|
||||||
if (offset > prevOffset && offset <= endOffset) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ordinal = prevOrdinal + offset - endOffset;
|
|
||||||
}
|
|
||||||
return new DataTypeComponentImpl(DataType.DEFAULT, this, 1, ordinal, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSplitOffset() {
|
|
||||||
return splitOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getNegativeLength() {
|
|
||||||
return negativeLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPositiveLength() {
|
|
||||||
return positiveLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(int index) {
|
|
||||||
if (index < 0 || index >= numComponents) {
|
|
||||||
throw new IndexOutOfBoundsException(index);
|
|
||||||
}
|
|
||||||
DataTypeComponent comp = getComponent(index);
|
|
||||||
int offset = comp.getOffset();
|
|
||||||
int length = comp.getLength();
|
|
||||||
int idx = Collections.binarySearch(components, index, ordinalComparator);
|
|
||||||
if (idx >= 0) {
|
|
||||||
DataTypeComponent dtc = components.remove(idx);
|
|
||||||
dtc.getDataType().removeParent(this);
|
|
||||||
length = dtc.getLength();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
idx = -idx - 1;
|
|
||||||
length = 1;
|
|
||||||
}
|
|
||||||
adjustOffsets(idx, offset, -1, -length);
|
|
||||||
numComponents--;
|
|
||||||
notifySizeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(Set<Integer> ordinals) {
|
|
||||||
for (int ordinal : ordinals) {
|
|
||||||
delete(ordinal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param idx the min index in the defined component arraylist
|
|
||||||
* @param offset
|
|
||||||
* @param deltaOrdinal
|
|
||||||
* @param deltaLength
|
|
||||||
*/
|
|
||||||
protected void adjustOffsets(int idx, int offset, int deltaOrdinal, int deltaLength) {
|
|
||||||
if (offset >= splitOffset) {
|
|
||||||
// component was in positive offsets
|
|
||||||
shiftOffsets(idx, deltaOrdinal, deltaLength);
|
|
||||||
positiveLength += deltaLength;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (offset - deltaLength > splitOffset) {
|
|
||||||
// The deleted component straddled negative/zero boudary.
|
|
||||||
shiftOffsets(0, idx - 1, 0, offset);
|
|
||||||
shiftOffsets(idx, deltaOrdinal, offset - deltaLength);
|
|
||||||
// TODO: this seems wrong
|
|
||||||
negativeLength += offset;
|
|
||||||
positiveLength -= (offset - deltaLength);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// component was in negative offsets
|
|
||||||
shiftOffsets(0, idx - 1, 0, -deltaLength);
|
|
||||||
shiftOffsets(idx, deltaOrdinal, 0);
|
|
||||||
negativeLength += deltaLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
structLength += deltaLength;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private void shiftOffsets(int index, int deltaOrdinal, int deltaOffset) {
|
|
||||||
shiftOffsets(index, components.size() - 1, deltaOrdinal, deltaOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param startIndex the min index in the defined component arraylist
|
|
||||||
* @param endIndex the max index in the defined component arraylist
|
|
||||||
* @param deltaOrdinal
|
|
||||||
* @param deltaOffset
|
|
||||||
*/
|
|
||||||
protected void shiftOffsets(int startIndex, int endIndex, int deltaOrdinal, int deltaOffset) {
|
|
||||||
for (int i = startIndex; i <= endIndex && i < components.size(); i++) {
|
|
||||||
DataTypeComponentImpl dtc = components.get(i);
|
|
||||||
shiftOffset(dtc, deltaOrdinal, deltaOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DataTypeComponent getDefinedComponent(int ordinal) {
|
|
||||||
if (ordinal < 0 || ordinal >= numComponents) {
|
|
||||||
throw new IndexOutOfBoundsException(ordinal);
|
|
||||||
}
|
|
||||||
int idx = Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
|
|
||||||
if (idx >= 0) {
|
|
||||||
return components.get(idx);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponentImpl getComponent(int ordinal) {
|
|
||||||
if (ordinal < 0 || ordinal >= numComponents) {
|
|
||||||
throw new IndexOutOfBoundsException(ordinal);
|
|
||||||
}
|
|
||||||
int idx = Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
|
|
||||||
if (idx >= 0) {
|
|
||||||
return components.get(idx);
|
|
||||||
}
|
|
||||||
idx = -idx - 1;
|
|
||||||
int prevIndex = idx - 1;
|
|
||||||
int offset = computeOffset(ordinal, prevIndex);
|
|
||||||
return new DataTypeComponentImpl(DataType.DEFAULT, this, 1, ordinal, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int computeOffset(int ordinal, int prevIndex) {
|
|
||||||
int offset;
|
|
||||||
if (prevIndex < 0) {
|
|
||||||
offset = splitOffset - negativeLength + ordinal;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DataTypeComponent prevElement = components.get(prevIndex);
|
|
||||||
int prevOrdinal = prevElement.getOrdinal();
|
|
||||||
int endOffset = prevElement.getEndOffset();
|
|
||||||
offset = endOffset + ordinal - prevOrdinal;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getNumComponents() {
|
|
||||||
return numComponents;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponentImpl insertAtOffset(int offset, DataType dataType, int length,
|
|
||||||
String newName, String comment) throws IllegalArgumentException {
|
|
||||||
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Offset " + offset + " is not in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
validateDataType(dataType);
|
|
||||||
int nextOffset = offset + length;
|
|
||||||
if (offset > positiveLength) {
|
|
||||||
int deltaLength = offset - positiveLength;
|
|
||||||
numComponents += deltaLength;
|
|
||||||
positiveLength += deltaLength;
|
|
||||||
structLength += deltaLength;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
}
|
|
||||||
if (nextOffset < splitOffset - negativeLength) {
|
|
||||||
int deltaLength = splitOffset - nextOffset - negativeLength;
|
|
||||||
numComponents += deltaLength;
|
|
||||||
negativeLength += deltaLength;
|
|
||||||
structLength += deltaLength;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
}
|
|
||||||
checkAncestry(dataType);
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
|
||||||
|
|
||||||
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
|
|
||||||
|
|
||||||
int additionalShift = 0;
|
|
||||||
if (index >= 0) {
|
|
||||||
DataTypeComponent dtc = components.get(index);
|
|
||||||
if (offset < 0) {
|
|
||||||
additionalShift = offset - dtc.getEndOffset();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
additionalShift = offset - dtc.getOffset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
index = -index - 1;
|
|
||||||
}
|
|
||||||
// TODO: ??
|
|
||||||
int ordinal = negativeLength + offset;
|
|
||||||
if (index > 0) {
|
|
||||||
DataTypeComponent dtc = components.get(index - 1);
|
|
||||||
ordinal = dtc.getOrdinal() + offset - dtc.getEndOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataTypeComponentImpl dtc =
|
|
||||||
new DataTypeComponentImpl(dataType, this, length, ordinal, offset, newName, comment);
|
|
||||||
dataType.addParent(this);
|
|
||||||
adjustOffsets(index, offset, 1 + additionalShift, dtc.getLength() + additionalShift);
|
|
||||||
components.add(index, dtc);
|
|
||||||
numComponents++;
|
|
||||||
notifySizeChanged();
|
|
||||||
return dtc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent add(DataType dataType, int length, String newName, String comment) {
|
|
||||||
return addPositive(dataType, length, newName, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent addPositive(DataType dataType, int length, String newName,
|
|
||||||
String comment) throws IllegalArgumentException {
|
|
||||||
|
|
||||||
validateDataType(dataType);
|
|
||||||
checkAncestry(dataType);
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
|
||||||
// int dtLength = dataType.getLength();
|
|
||||||
|
|
||||||
int offset = positiveLength;
|
|
||||||
DataTypeComponentImpl dtc = new DataTypeComponentImpl(dataType, this, length, numComponents,
|
|
||||||
offset, newName, comment);
|
|
||||||
dataType.addParent(this);
|
|
||||||
components.add(dtc);
|
|
||||||
numComponents++;
|
|
||||||
positiveLength += length;
|
|
||||||
structLength += length;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
notifySizeChanged();
|
|
||||||
return dtc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent addNegative(DataType dataType, int length, String newName,
|
|
||||||
String comment) throws IllegalArgumentException {
|
|
||||||
|
|
||||||
validateDataType(dataType);
|
|
||||||
checkAncestry(dataType);
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
|
||||||
// int dtLength = dataType.getLength();
|
|
||||||
|
|
||||||
shiftOffsets(0, numComponents - 1, 1, 0);
|
|
||||||
int offset = splitOffset - negativeLength - length;
|
|
||||||
DataTypeComponentImpl dtc =
|
|
||||||
new DataTypeComponentImpl(dataType, this, length, 0, offset, newName, comment);
|
|
||||||
dataType.addParent(this);
|
|
||||||
components.add(dtc);
|
|
||||||
numComponents++;
|
|
||||||
negativeLength += length;
|
|
||||||
structLength += length;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
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
|
|
||||||
* offset side will grow by the indicated amount. If amount is negative, the data type grows on
|
|
||||||
* the negative offsets side.
|
|
||||||
*
|
|
||||||
* @param amount Positive value indicates number of bytes to add to positive side. Negative
|
|
||||||
* value indicates number of bytes to add to negative side.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void growStructure(int amount) {
|
|
||||||
int absAmount;
|
|
||||||
if (amount < 0) {
|
|
||||||
absAmount = -amount;
|
|
||||||
negativeLength -= amount;
|
|
||||||
adjustOffsets(0, negativeLength, absAmount, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
absAmount = amount;
|
|
||||||
positiveLength += amount;
|
|
||||||
}
|
|
||||||
numComponents += absAmount;
|
|
||||||
structLength += absAmount;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
notifySizeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent insert(int index, DataType dataType, int length, String newName,
|
|
||||||
String comment) {
|
|
||||||
throw new UnsupportedOperationException("BiDirectionDataType.insert() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void insertAtOffset(int offset, int numBytes) {
|
|
||||||
if (offset < splitOffset - negativeLength || offset > splitOffset + positiveLength) {
|
|
||||||
throw new IllegalArgumentException("Offset " + offset +
|
|
||||||
" is not a valid insertion point in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
DataTypeComponent dtc = getComponentAt(offset);
|
|
||||||
int numDefinedComponents = components.size();
|
|
||||||
int definedIndex = 0;
|
|
||||||
if (dtc == null) {
|
|
||||||
if (offset == positiveLength) {
|
|
||||||
definedIndex = numDefinedComponents;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("Offset " + offset +
|
|
||||||
" is not a valid insertion point in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dtc.getOffset() != offset) {
|
|
||||||
throw new IllegalArgumentException("Cannot insert at offset " + offset +
|
|
||||||
" within a defined component in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
definedIndex = Collections.binarySearch(components, Integer.valueOf(dtc.getOrdinal()),
|
|
||||||
ordinalComparator);
|
|
||||||
if (definedIndex < 0) {
|
|
||||||
definedIndex = -definedIndex - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (offset <= 0) {
|
|
||||||
shiftOffsets(0, definedIndex - 1, 0, -numBytes);
|
|
||||||
shiftOffsets(definedIndex, numDefinedComponents - 1, numBytes, 0);
|
|
||||||
negativeLength += numBytes;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
shiftOffsets(definedIndex, numDefinedComponents - 1, numBytes, numBytes);
|
|
||||||
positiveLength += numBytes;
|
|
||||||
}
|
|
||||||
numComponents += numBytes;
|
|
||||||
structLength += numBytes;
|
|
||||||
// nonpackedAlignedStructLength = -1;
|
|
||||||
notifySizeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAtOffset(int offset) {
|
|
||||||
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Offset " + offset + " is not in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
|
|
||||||
|
|
||||||
int length = 1;
|
|
||||||
if (index < 0) {
|
|
||||||
index = -index - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DataTypeComponent dtc = components.remove(index);
|
|
||||||
dtc.getDataType().removeParent(this);
|
|
||||||
length = dtc.getLength();
|
|
||||||
}
|
|
||||||
adjustOffsets(index, offset, -1, -length);
|
|
||||||
numComponents--;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearAtOffset(int offset) {
|
|
||||||
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Offset " + offset + " is not in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
|
|
||||||
if (index >= 0) {
|
|
||||||
DataTypeComponent dtc = components.remove(index);
|
|
||||||
dtc.getDataType().removeParent(this);
|
|
||||||
int len = dtc.getLength();
|
|
||||||
if (len > 1) {
|
|
||||||
int deltaLength = len - 1;
|
|
||||||
shiftOffsets(index, deltaLength, 0);
|
|
||||||
numComponents += deltaLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEquivalent(DataType dataType) {
|
|
||||||
if (dataType == this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (dataType == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataType instanceof BiDirectionStructure) {
|
|
||||||
BiDirectionStructure biDir = (BiDirectionStructure) dataType;
|
|
||||||
if ((splitOffset != biDir.getSplitOffset()) ||
|
|
||||||
(negativeLength != biDir.getNegativeLength()) ||
|
|
||||||
(positiveLength != biDir.getPositiveLength()) ||
|
|
||||||
(getLength() != biDir.getLength())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DataTypeComponent[] myComps = getDefinedComponents();
|
|
||||||
DataTypeComponent[] otherComps = biDir.getDefinedComponents();
|
|
||||||
if (myComps.length != otherComps.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < myComps.length; i++) {
|
|
||||||
if (!myComps[i].isEquivalent(otherComps[i])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeSizeChanged(DataType dt) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeAlignmentChanged(DataType dt) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract BiDirectionDataType clone(DataTypeManager dtm);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearComponent(int ordinal) {
|
|
||||||
if (ordinal < 0 || ordinal >= numComponents) {
|
|
||||||
throw new IndexOutOfBoundsException(ordinal);
|
|
||||||
}
|
|
||||||
int index =
|
|
||||||
Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
|
|
||||||
if (index >= 0) {
|
|
||||||
DataTypeComponent dtc = components.remove(index);
|
|
||||||
dtc.getDataType().removeParent(this);
|
|
||||||
int len = dtc.getLength();
|
|
||||||
if (len > 1) {
|
|
||||||
int deltaLength = len - 1;
|
|
||||||
shiftOffsets(index, deltaLength, 0);
|
|
||||||
numComponents += deltaLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replaceWith(Structure struct) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"BiDirectionDataType.replaceWith() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeDeleted(DataType dt) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"BiDirectionDataType.dataTypeDeleted() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"BiDirectionDataType.dataTypeReplaced() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent[] getDefinedComponents() {
|
|
||||||
return components.toArray(new DataTypeComponent[components.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent[] getComponents() {
|
|
||||||
DataTypeComponent[] comps = new DataTypeComponent[numComponents];
|
|
||||||
for (int i = 0; i < comps.length; i++) {
|
|
||||||
comps[i] = getComponent(i);
|
|
||||||
}
|
|
||||||
return comps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent replace(int index, DataType dataType, int length, String newName,
|
|
||||||
String comment) throws IndexOutOfBoundsException, IllegalArgumentException {
|
|
||||||
if (index < 0 || index >= numComponents) {
|
|
||||||
throw new IndexOutOfBoundsException(index);
|
|
||||||
}
|
|
||||||
validateDataType(dataType);
|
|
||||||
checkAncestry(dataType);
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
|
||||||
DataTypeComponent origDtc = getComponent(index);
|
|
||||||
return replace(origDtc, dataType, length, newName, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length,
|
|
||||||
String newName, String comment) throws IllegalArgumentException {
|
|
||||||
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Offset " + offset + " is not in " + getDisplayName() + ".");
|
|
||||||
}
|
|
||||||
validateDataType(dataType);
|
|
||||||
checkAncestry(dataType);
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
|
||||||
DataTypeComponent origDtc = getComponentAt(offset);
|
|
||||||
DataTypeComponent newDtc = replace(origDtc, dataType, length, newName, comment);
|
|
||||||
return newDtc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the indicated component with a new component containing the specified data type.
|
|
||||||
*
|
|
||||||
* @param origDtc the original data type component in this structure.
|
|
||||||
* @param dataType the data type of the new component
|
|
||||||
* @param length the length of the new component
|
|
||||||
* @param newName the field name of the new component
|
|
||||||
* @param comment the comment for the new component
|
|
||||||
* @return the new component or null if the new component couldn't fit.
|
|
||||||
* @throws IllegalArgumentException if the dataType.getLength() is positive and does not match
|
|
||||||
* the given length parameter.
|
|
||||||
* @throws IllegalArgumentException if the specified data type is not allowed to replace a
|
|
||||||
* component in this composite data type. For example, suppose dt1 contains dt2.
|
|
||||||
* Therefore it is not valid to replace a dt2 component with dt1 since this would
|
|
||||||
* cause a cyclic dependency.
|
|
||||||
*/
|
|
||||||
private DataTypeComponent replace(DataTypeComponent origDtc, DataType dataType, int length,
|
|
||||||
String newName, String comment) {
|
|
||||||
|
|
||||||
int ordinal = origDtc.getOrdinal();
|
|
||||||
int newOffset = origDtc.getOffset();
|
|
||||||
int dtcLength = origDtc.getLength();
|
|
||||||
int bytesNeeded = length - dtcLength;
|
|
||||||
int deltaOrdinal = -bytesNeeded;
|
|
||||||
if (bytesNeeded > 0) {
|
|
||||||
int bytesAvailable = getNumUndefinedBytes(ordinal + 1);
|
|
||||||
if (bytesAvailable < bytesNeeded) {
|
|
||||||
// throw new IllegalArgumentException("Not enough undefined bytes.");
|
|
||||||
deltaOrdinal = -bytesAvailable;
|
|
||||||
length -= (bytesNeeded - bytesAvailable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
origDtc.getDataType().removeParent(this);
|
|
||||||
DataTypeComponentImpl newDtc =
|
|
||||||
new DataTypeComponentImpl(dataType, this, length, ordinal, newOffset, newName, comment);
|
|
||||||
dataType.addParent(this);
|
|
||||||
int index =
|
|
||||||
Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
|
|
||||||
if (index < 0) {
|
|
||||||
index = -index - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
components.remove(index);
|
|
||||||
}
|
|
||||||
if (deltaOrdinal != 0) {
|
|
||||||
adjustOffsets(index, newOffset, deltaOrdinal, 0);
|
|
||||||
}
|
|
||||||
components.add(index, newDtc);
|
|
||||||
if (deltaOrdinal != 0) {
|
|
||||||
numComponents += deltaOrdinal;
|
|
||||||
}
|
|
||||||
return newDtc;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class OffsetComparator implements Comparator<Object> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Object o1, Object o2) {
|
|
||||||
if (o1 instanceof Integer) {
|
|
||||||
return -compare(o2, o1);
|
|
||||||
}
|
|
||||||
DataTypeComponent dtc = (DataTypeComponent) o1;
|
|
||||||
int offset = ((Integer) o2).intValue();
|
|
||||||
if (offset < dtc.getOffset()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (offset > dtc.getEndOffset()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrdinalComparator implements Comparator<Object> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Object o1, Object o2) {
|
|
||||||
if (o1 instanceof Integer) {
|
|
||||||
return -compare(o2, o1);
|
|
||||||
}
|
|
||||||
DataTypeComponent dtc = (DataTypeComponent) o1;
|
|
||||||
int ordinal = ((Integer) o2).intValue();
|
|
||||||
return dtc.getOrdinal() - ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
/* ###
|
|
||||||
* 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.stackeditor;
|
|
||||||
|
|
||||||
import ghidra.program.model.data.*;
|
|
||||||
|
|
||||||
public interface BiDirectionStructure extends Structure {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the length of this DataType in the negative direction.
|
|
||||||
* @return the length of this DataType in the negative direction.
|
|
||||||
*/
|
|
||||||
public abstract int getNegativeLength();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the length of this DataType in the positive direction.
|
|
||||||
* @return the length of this DataType in the positive direction.
|
|
||||||
*/
|
|
||||||
public abstract int getPositiveLength();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the component offset which represents the division point
|
|
||||||
* between the positive and negative halves of the structure.
|
|
||||||
* @return split offset
|
|
||||||
*/
|
|
||||||
public abstract int getSplitOffset();
|
|
||||||
|
|
||||||
public DataTypeComponent addNegative(DataType dataType, int length, String name, String comment);
|
|
||||||
|
|
||||||
public DataTypeComponent addPositive(DataType dataType, int length, String name, String comment);
|
|
||||||
}
|
|
|
@ -17,8 +17,6 @@ package ghidra.app.plugin.core.stackeditor;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
|
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.fieldpanel.support.FieldRange;
|
import docking.widgets.fieldpanel.support.FieldRange;
|
||||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
import docking.widgets.fieldpanel.support.FieldSelection;
|
||||||
|
@ -32,7 +30,9 @@ import docking.widgets.fieldpanel.support.FieldSelection;
|
||||||
* When edit actions occur and there is a selection, the listener's are notified
|
* When edit actions occur and there is a selection, the listener's are notified
|
||||||
* of the new selection via the listener's overrideSelection method.
|
* of the new selection via the listener's overrideSelection method.
|
||||||
*/
|
*/
|
||||||
import ghidra.app.plugin.core.compositeeditor.*;
|
import ghidra.app.plugin.core.compositeeditor.CompositeEditorModel;
|
||||||
|
import ghidra.app.plugin.core.compositeeditor.CompositeViewerDataTypeManager;
|
||||||
|
import ghidra.app.plugin.core.stackeditor.StackFrameDataType.StackComponentWrapper;
|
||||||
import ghidra.app.util.datatype.EmptyCompositeException;
|
import ghidra.app.util.datatype.EmptyCompositeException;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
import ghidra.framework.plugintool.Plugin;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
@ -57,7 +57,8 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
private static final int MAX_LOCAL_SIZE = Integer.MAX_VALUE;
|
private static final int MAX_LOCAL_SIZE = Integer.MAX_VALUE;
|
||||||
private static final int MAX_PARAM_SIZE = Integer.MAX_VALUE;
|
private static final int MAX_PARAM_SIZE = Integer.MAX_VALUE;
|
||||||
|
|
||||||
private StackFrame originalStack;
|
private Function function;
|
||||||
|
private StackFrameDataType originalStackFrameDataType;
|
||||||
|
|
||||||
private boolean stackChangedExternally;
|
private boolean stackChangedExternally;
|
||||||
|
|
||||||
|
@ -91,16 +92,23 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stackChangedExternally(boolean changed) {
|
@Override
|
||||||
stackChangedExternally = changed;
|
protected boolean usesAlignedLengthComponents() {
|
||||||
|
// NOTE: It is assumed that aligned-length is not used by stack variables
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(Function function) {
|
void stackChangedExternally(boolean changed) {
|
||||||
originalStack = function.getStackFrame();
|
stackChangedExternally = changed;
|
||||||
ProgramBasedDataTypeManager dtm = function.getProgram().getDataTypeManager();
|
if (changed) {
|
||||||
StackFrameDataType stackFrameDataType = new StackFrameDataType(originalStack, dtm);
|
setStatus("Stack may have been changed externally -- data may be stale.");
|
||||||
stackFrameDataType.setCategoryPath(dtm.getRootCategory().getCategoryPath());
|
}
|
||||||
load(stackFrameDataType);
|
}
|
||||||
|
|
||||||
|
void load(Function func) {
|
||||||
|
function = func;
|
||||||
|
originalStackFrameDataType = new StackFrameDataType(function);
|
||||||
|
load(originalStackFrameDataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,18 +118,27 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createViewCompositeFromOriginalComposite(StackFrameDataType original) {
|
protected void createViewCompositeFromOriginalComposite() {
|
||||||
|
|
||||||
if (viewDTM != null) {
|
if (viewDTM != null) {
|
||||||
viewDTM.close();
|
viewDTM.close();
|
||||||
viewDTM = null;
|
viewDTM = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use temporary standalone view datatype manager which will not manage the viewComposite
|
// Establish editor's datatype manager which will manage datatype dependencies.
|
||||||
viewDTM = new CompositeViewerDataTypeManager<>(originalDTM.getName(), originalDTM);
|
viewDTM = new CompositeViewerDataTypeManager<>(originalDTM.getName(), originalDTM);
|
||||||
|
|
||||||
// NOTE: StackFrameDataType cannot be resolved but all of its element datatypes must be
|
// Create a copy of the original stack frame datatype and force the resolving of its
|
||||||
viewComposite = original.copy(viewDTM);
|
// datatype dependencies. A round-about approach is used since the StackFrameDataType
|
||||||
|
// itself cannot be resolved and cannot be treated in the same fashion as a normal
|
||||||
|
// Structure edit. It relies on wrapping a normal structure to serve as a proxy of sorts
|
||||||
|
// for the purpose of managing datatype dependencies. It is only through the use of
|
||||||
|
// a StructureDB that component datatypes are forced to be resolved into the viewDTM.
|
||||||
|
// NOTE: Since the StackEditorDataTypeManager keeps a single transaction open unused
|
||||||
|
// datatype pruning is never performed.
|
||||||
|
viewComposite = originalComposite.copy(originalDTM);
|
||||||
|
originalComposite.resolveWrappedComposite(viewDTM);
|
||||||
|
originalComposite = originalStackFrameDataType; // use true original
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,18 +148,15 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateAndCheckChangeState() {
|
public boolean updateAndCheckChangeState() {
|
||||||
if (originalIsChanging) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
StackFrameDataType sfdt = viewComposite;
|
StackFrameDataType sfdt = viewComposite;
|
||||||
int editReturnAddressOffset = sfdt.getReturnAddressOffset();
|
int editReturnAddressOffset = sfdt.getReturnAddressOffset();
|
||||||
int editLocalSize = sfdt.getLocalSize();
|
int editLocalSize = sfdt.getLocalSize();
|
||||||
int editParamOffset = sfdt.getParameterOffset();
|
int editParamOffset = sfdt.getParameterOffset();
|
||||||
int editParamSize = sfdt.getParameterSize();
|
int editParamSize = sfdt.getParameterSize();
|
||||||
int stackReturnAddressOffset = originalStack.getReturnAddressOffset();
|
int stackReturnAddressOffset = originalStackFrameDataType.getReturnAddressOffset();
|
||||||
int stackLocalSize = originalStack.getLocalSize();
|
int stackLocalSize = originalStackFrameDataType.getLocalSize();
|
||||||
int stackParamOffset = originalStack.getParameterOffset();
|
int stackParamOffset = originalStackFrameDataType.getParameterOffset();
|
||||||
int stackParamSize = originalStack.getParameterSize();
|
int stackParamSize = originalStackFrameDataType.getParameterSize();
|
||||||
hasChanges = (editReturnAddressOffset != stackReturnAddressOffset) ||
|
hasChanges = (editReturnAddressOffset != stackReturnAddressOffset) ||
|
||||||
(editLocalSize != stackLocalSize) || (editParamOffset != stackParamOffset) ||
|
(editLocalSize != stackLocalSize) || (editParamOffset != stackParamOffset) ||
|
||||||
(editParamSize != stackParamSize) || super.updateAndCheckChangeState();
|
(editParamSize != stackParamSize) || super.updateAndCheckChangeState();
|
||||||
|
@ -185,7 +199,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
(rowIndex < 0) || (columnIndex < 0) || (columnIndex >= getColumnCount())) {
|
(rowIndex < 0) || (columnIndex < 0) || (columnIndex >= getColumnCount())) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
DataTypeComponent element = viewComposite.getComponent(rowIndex);
|
StackComponentWrapper element = viewComposite.getComponent(rowIndex);
|
||||||
DataType dt;
|
DataType dt;
|
||||||
int dtLen;
|
int dtLen;
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
|
@ -214,10 +228,6 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
if (fieldName == null) {
|
if (fieldName == null) {
|
||||||
fieldName = "";
|
fieldName = "";
|
||||||
}
|
}
|
||||||
// if ((fieldName.length() == 0)
|
|
||||||
// && (element.getOffset() == ((StackFrameDataType)viewComposite).getReturnAddressOffset())) {
|
|
||||||
// return "<RETURN_ADDRESS>";
|
|
||||||
// }
|
|
||||||
return fieldName;
|
return fieldName;
|
||||||
case COMMENT:
|
case COMMENT:
|
||||||
return element.getComment();
|
return element.getComment();
|
||||||
|
@ -226,13 +236,13 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFieldNameAtRow(int rowIndex, StackFrameDataType stackFrameDataType) {
|
private String getFieldNameAtRow(int rowIndex, StackFrameDataType stackDt) {
|
||||||
DataTypeComponent dataType = stackFrameDataType.getComponent(rowIndex);
|
StackComponentWrapper stackDtc = stackDt.getComponent(rowIndex);
|
||||||
String fieldName = dataType.getFieldName();
|
String fieldName = stackDtc.getFieldName();
|
||||||
if (fieldName == null) {
|
if (fieldName == null) {
|
||||||
// If the component is a defined stack variable with no name, use default name.
|
// If the component is a defined stack variable with no name, use default name.
|
||||||
if (stackFrameDataType.isStackVariable(rowIndex)) {
|
if (stackDt.isStackVariable(rowIndex)) {
|
||||||
fieldName = stackFrameDataType.getDefaultName(dataType);
|
fieldName = stackDt.getDefaultName(stackDtc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fieldName;
|
return fieldName;
|
||||||
|
@ -249,23 +259,12 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
public void setValueAt(Object aValue, int rowIndex, int modelColumnIndex) {
|
public void setValueAt(Object aValue, int rowIndex, int modelColumnIndex) {
|
||||||
try {
|
try {
|
||||||
settingValueAt = true;
|
settingValueAt = true;
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
|
||||||
|
|
||||||
Object originalValue = getValueAt(rowIndex, modelColumnIndex);
|
Object originalValue = getValueAt(rowIndex, modelColumnIndex);
|
||||||
if (SystemUtilities.isEqual(originalValue, aValue)) {
|
if (SystemUtilities.isEqual(originalValue, aValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
fieldEdited(aValue, rowIndex, modelColumnIndex);
|
||||||
if (fieldEdited(aValue, rowIndex, modelColumnIndex)) {
|
setSelection(new int[] { rowIndex });
|
||||||
if (modelColumnIndex == OFFSET) {
|
|
||||||
int svOffset = Integer.decode((String) aValue).intValue();
|
|
||||||
DataTypeComponent dtc =
|
|
||||||
(viewComposite).getComponentAt(svOffset);
|
|
||||||
offsetSelection = new OffsetPairs();
|
|
||||||
offsetSelection.addPair(svOffset, dtc.getEndOffset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setRelOffsetSelection(offsetSelection);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
settingValueAt = false;
|
settingValueAt = false;
|
||||||
|
@ -292,9 +291,6 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
setComponentOffset(rowIndex, (String) value);
|
setComponentOffset(rowIndex, (String) value);
|
||||||
break;
|
break;
|
||||||
case DATATYPE:
|
case DATATYPE:
|
||||||
if (value instanceof StackPieceDataType) {
|
|
||||||
return true; // no change
|
|
||||||
}
|
|
||||||
setComponentDataType(rowIndex, value);
|
setComponentDataType(rowIndex, value);
|
||||||
break;
|
break;
|
||||||
case NAME:
|
case NAME:
|
||||||
|
@ -424,10 +420,6 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
return viewComposite.getDefinedComponentAtOffset(offset) != null;
|
return viewComposite.getDefinedComponentAtOffset(offset) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
StackFrame getOriginalStack() {
|
|
||||||
return originalStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
StackFrameDataType getEditorStack() {
|
StackFrameDataType getEditorStack() {
|
||||||
return viewComposite;
|
return viewComposite;
|
||||||
}
|
}
|
||||||
|
@ -603,10 +595,13 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isAddAllowed(int currentIndex, DataType dataType) {
|
public boolean isAddAllowed(int currentIndex, DataType dataType) {
|
||||||
|
|
||||||
|
if (currentIndex < 0 || currentIndex >= getRowCount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (currentIndex < 0 || currentIndex >= getRowCount()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
checkIsAllowableDataType(dataType);
|
checkIsAllowableDataType(dataType);
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
|
@ -627,18 +622,6 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
newLength = compDt.getLength();
|
newLength = compDt.getLength();
|
||||||
}
|
}
|
||||||
int offset = comp.getOffset();
|
int offset = comp.getOffset();
|
||||||
// TODO: not sure we need to prevent creating local variables in 'save' area,
|
|
||||||
// since doing so just leads to confusion when using stack frame editor
|
|
||||||
// if (((StackFrameDataType) viewComposite).growsNegative()) {
|
|
||||||
// if (offset >= 0 && offset < getParameterOffset()) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// if (offset < 0 && offset > getParameterOffset()) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
int maxBytes = viewComposite.getMaxLength(offset);
|
int maxBytes = viewComposite.getMaxLength(offset);
|
||||||
if (newLength > maxBytes) {
|
if (newLength > maxBytes) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -660,7 +643,8 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
if (index < 0 || index >= viewComposite.getNumComponents()) {
|
if (index < 0 || index >= viewComposite.getNumComponents()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return viewComposite.getDefinedComponentAtOrdinal(index) != null;
|
StackComponentWrapper dtc = viewComposite.getDefinedComponentAtOrdinal(index);
|
||||||
|
return dtc != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -683,17 +667,8 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int paramOffset = getParameterOffset();
|
int paramOffset = getParameterOffset();
|
||||||
if (paramOffset >= 0) {
|
if (startOffset < paramOffset && endOffset >= paramOffset) {
|
||||||
// grows negative
|
return false;
|
||||||
if (startOffset < paramOffset && endOffset >= paramOffset) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// grows positive
|
|
||||||
if (startOffset <= paramOffset && endOffset > paramOffset) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -723,59 +698,6 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustComponents(DataType dataType) {
|
|
||||||
DataTypeComponent[] comps = viewComposite.getDefinedComponents();
|
|
||||||
String msg = "";
|
|
||||||
for (DataTypeComponent component : comps) {
|
|
||||||
DataType compDt = component.getDataType();
|
|
||||||
if (compDt == dataType) {
|
|
||||||
int len = compDt.getLength();
|
|
||||||
if (len <= 0) {
|
|
||||||
len = component.getLength();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
viewComposite.replace(component.getOrdinal(), compDt, len,
|
|
||||||
component.getFieldName(),
|
|
||||||
component.getComment());
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
msg += "Adjusting variable at offset " +
|
|
||||||
getHexString(component.getOffset(), true) + ". " + e.getMessage() + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (msg.length() > 0) {
|
|
||||||
JOptionPane.showMessageDialog(provider.getComponent(), msg,
|
|
||||||
"Stack Editor Adjustment Warning", JOptionPane.WARNING_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void replaceComponents(DataType oldDataType, DataType newDataType) {
|
|
||||||
DataTypeComponent[] comps = viewComposite.getDefinedComponents();
|
|
||||||
String msg = "";
|
|
||||||
for (DataTypeComponent component : comps) {
|
|
||||||
DataType compDt = component.getDataType();
|
|
||||||
if (compDt == oldDataType) {
|
|
||||||
int len = newDataType.getLength();
|
|
||||||
if (len <= 0) {
|
|
||||||
len = component.getLength();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
viewComposite.replace(component.getOrdinal(), newDataType, len,
|
|
||||||
component.getFieldName(), component.getComment());
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
msg += "Replacing variable at offset " +
|
|
||||||
getHexString(component.getOffset(), true) + ". " + e.getMessage() + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (msg.length() > 0) {
|
|
||||||
JOptionPane.showMessageDialog(provider.getComponent(), msg,
|
|
||||||
"Stack Editor Replacement Warning", JOptionPane.WARNING_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setComponentDataTypeInstance(int index, DataType dt, int length)
|
public void setComponentDataTypeInstance(int index, DataType dt, int length)
|
||||||
throws UsrException {
|
throws UsrException {
|
||||||
|
@ -800,15 +722,14 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
|
|
||||||
// prevent user names that are default values, unless the value is the original name
|
// prevent user names that are default values, unless the value is the original name
|
||||||
String nameInEditor = (String) getValueAt(rowIndex, NAME);
|
String nameInEditor = (String) getValueAt(rowIndex, NAME);
|
||||||
StackFrameDataType stackFrameDataType = viewComposite;
|
if (viewComposite.isDefaultName(newName) && !isOriginalFieldName(newName, rowIndex)) {
|
||||||
if (stackFrameDataType.isDefaultName(newName) && !isOriginalFieldName(newName, rowIndex)) {
|
|
||||||
if (Objects.equals(nameInEditor, newName)) {
|
if (Objects.equals(nameInEditor, newName)) {
|
||||||
return false; // same as current name in the table; do nothing
|
return false; // same as current name in the table; do nothing
|
||||||
}
|
}
|
||||||
throw new InvalidNameException("Cannot set a stack variable name to a default value");
|
throw new InvalidNameException("Cannot set a stack variable name to a default value");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackFrameDataType.setName(rowIndex, newName)) {
|
if (viewComposite.setName(rowIndex, newName)) {
|
||||||
updateAndCheckChangeState();
|
updateAndCheckChangeState();
|
||||||
fireTableCellUpdated(rowIndex, getNameColumn());
|
fireTableCellUpdated(rowIndex, getNameColumn());
|
||||||
notifyCompositeChanged();
|
notifyCompositeChanged();
|
||||||
|
@ -819,8 +740,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
|
|
||||||
/** Gets the original field name within the parent data type for a given row in the editor */
|
/** Gets the original field name within the parent data type for a given row in the editor */
|
||||||
private boolean isOriginalFieldName(String testName, int rowIndex) {
|
private boolean isOriginalFieldName(String testName, int rowIndex) {
|
||||||
StackFrameDataType dataType = getOriginalComposite();
|
String fieldName = getFieldNameAtRow(rowIndex, originalStackFrameDataType);
|
||||||
String fieldName = getFieldNameAtRow(rowIndex, dataType);
|
|
||||||
return SystemUtilities.isEqual(fieldName, testName);
|
return SystemUtilities.isEqual(fieldName, testName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,6 +777,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent add(int index, DataType dt) throws UsrException {
|
public DataTypeComponent add(int index, DataType dt) throws UsrException {
|
||||||
|
// NOTE: Unused method
|
||||||
return replace(index, dt);
|
return replace(index, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,16 +830,14 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
if (!isValidName() || !hasChanges()) {
|
if (!isValidName() || !hasChanges()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StackFrame original = getOriginalStack(); // FIXME: Not Needed - use originalStack
|
|
||||||
Function function = original.getFunction();
|
|
||||||
StackFrameDataType edited = getEditorStack();
|
|
||||||
|
|
||||||
Variable[] newVars = edited.getStackVariables();
|
Variable[] newVars = viewComposite.getStackVariables();
|
||||||
List<Variable> newVarsList = Arrays.asList(newVars);
|
List<Variable> newVarsList = Arrays.asList(newVars);
|
||||||
Collections.sort(newVarsList, StackVariableComparator.get()); // sort for use with getVariableContaining
|
Collections.sort(newVarsList, StackVariableComparator.get()); // sort for use with getVariableContaining
|
||||||
|
|
||||||
original.setLocalSize(edited.getLocalSize());
|
StackFrame functionStackFrame = function.getStackFrame();
|
||||||
original.setReturnAddressOffset(edited.getReturnAddressOffset());
|
functionStackFrame.setLocalSize(viewComposite.getLocalSize());
|
||||||
|
functionStackFrame.setReturnAddressOffset(viewComposite.getReturnAddressOffset());
|
||||||
|
|
||||||
// first-pass: remove deleted params from end of param list if possible
|
// first-pass: remove deleted params from end of param list if possible
|
||||||
// to avoid custom storage enablement
|
// to avoid custom storage enablement
|
||||||
|
@ -959,7 +878,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
Variable newSv = null;
|
Variable newSv = null;
|
||||||
try {
|
try {
|
||||||
DataType dt = originalDTM.resolve(sv.getDataType(), null);
|
DataType dt = originalDTM.resolve(sv.getDataType(), null);
|
||||||
Variable var = original.getVariableContaining(sv.getStackOffset());
|
Variable var = functionStackFrame.getVariableContaining(sv.getStackOffset());
|
||||||
// TODO: Handle case where new size is smaller but stack alignment will prevent variable shuffle on setDataType - could be problamatic
|
// TODO: Handle case where new size is smaller but stack alignment will prevent variable shuffle on setDataType - could be problamatic
|
||||||
if (var != null && var.getStackOffset() == sv.getStackOffset() &&
|
if (var != null && var.getStackOffset() == sv.getStackOffset() &&
|
||||||
var.getLength() == sv.getLength()) {
|
var.getLength() == sv.getLength()) {
|
||||||
|
@ -972,16 +891,16 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (original.isParameterOffset(sv.getStackOffset()) ||
|
if (functionStackFrame.isParameterOffset(sv.getStackOffset()) ||
|
||||||
(var instanceof Parameter)) {
|
(var instanceof Parameter)) {
|
||||||
// about to make param change - must enable custom storage
|
// about to make param change - must enable custom storage
|
||||||
original.getFunction().setCustomVariableStorage(true);
|
functionStackFrame.getFunction().setCustomVariableStorage(true);
|
||||||
}
|
}
|
||||||
if (var != null) {
|
if (var != null) {
|
||||||
original.clearVariable(var.getStackOffset());
|
functionStackFrame.clearVariable(var.getStackOffset());
|
||||||
}
|
}
|
||||||
newSv = original.createVariable(sv.getName(), sv.getStackOffset(), dt,
|
newSv = functionStackFrame.createVariable(sv.getName(), sv.getStackOffset(),
|
||||||
SourceType.USER_DEFINED);
|
dt, SourceType.USER_DEFINED);
|
||||||
}
|
}
|
||||||
newSv.setComment(sv.getComment());
|
newSv.setComment(sv.getComment());
|
||||||
}
|
}
|
||||||
|
@ -1002,7 +921,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
newSv.setComment(comment);
|
newSv.setComment(comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
load(new StackFrameDataType(original, originalDTM));
|
load(function);
|
||||||
clearStatus();
|
clearStatus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1081,14 +1000,6 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataTypeComponent replace(DataType dataType) throws UsrException {
|
|
||||||
int rowIndex = getMinIndexSelected();
|
|
||||||
if (rowIndex < 0) {
|
|
||||||
throw new UsrException("A component must be selected.");
|
|
||||||
}
|
|
||||||
return replace(rowIndex, dataType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataTypeComponent replace(int index, DataType dataType) throws UsrException {
|
private DataTypeComponent replace(int index, DataType dataType) throws UsrException {
|
||||||
try {
|
try {
|
||||||
DataTypeInstance dti = getDropDataType(index, dataType);
|
DataTypeInstance dti = getDropDataType(index, dataType);
|
||||||
|
@ -1102,11 +1013,10 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent replace(int index, DataType dt, int dtLength) throws UsrException {
|
public DataTypeComponent replace(int index, DataType dt, int dtLength) throws UsrException {
|
||||||
|
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
|
||||||
fieldEdited(
|
fieldEdited(
|
||||||
DataTypeInstance.getDataTypeInstance(dt, dtLength, usesAlignedLengthComponents()),
|
DataTypeInstance.getDataTypeInstance(dt, dtLength, usesAlignedLengthComponents()),
|
||||||
index, getDataTypeColumn());
|
index, getDataTypeColumn());
|
||||||
setRelOffsetSelection(offsetSelection);
|
setSelection(new int[] { index });
|
||||||
return getComponent(index);
|
return getComponent(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1135,14 +1045,16 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restored(DataTypeManager dataTypeManager) {
|
public void restored(DataTypeManager dataTypeManager) {
|
||||||
|
functionChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void functionChanged(boolean isRestore) {
|
||||||
|
|
||||||
StackFrameDataType sfdt = getOriginalComposite();
|
|
||||||
Function function = sfdt.getFunction();
|
|
||||||
if (function.isDeleted()) {
|
if (function.isDeleted()) {
|
||||||
// Cancel Editor.
|
// Close the Editor.
|
||||||
provider.dispose();
|
|
||||||
PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool();
|
PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool();
|
||||||
tool.setStatusInfo("Stack Editor was closed for " + provider.getName());
|
tool.setStatusInfo("Stack Editor was closed for " + provider.getName());
|
||||||
|
provider.dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,9 +1064,9 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
if (hasChanges) {
|
if (hasChanges) {
|
||||||
// The user has modified the structure so prompt for whether or
|
// The user has modified the structure so prompt for whether or
|
||||||
// not to reload the structure.
|
// not to reload the structure.
|
||||||
String question = "The program \"dtm.getName()\" has been restored.\n" + "\"" +
|
String text = isRestore ? "may have " : "";
|
||||||
currentName + "\" may have changed outside the editor.\n" +
|
String question = "The function \"" + currentName + "\" " + text +
|
||||||
"Discard edits and reload the Stack Editor?";
|
"changed outside the editor.\n" + "Discard edits and reload the Stack Editor?";
|
||||||
String title = "Reload Stack Editor?";
|
String title = "Reload Stack Editor?";
|
||||||
int response = OptionDialog
|
int response = OptionDialog
|
||||||
.showYesNoDialogWithNoAsDefaultButton(provider.getComponent(), title, question);
|
.showYesNoDialogWithNoAsDefaultButton(provider.getComponent(), title, question);
|
||||||
|
@ -1166,10 +1078,83 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
load(function);
|
load(function);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
stackChangedExternally(true);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dataTypeRemoved(DataTypeManager dataTypeManager, DataTypePath path) {
|
||||||
|
|
||||||
|
if (dataTypeManager != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
|
||||||
|
if (dataType == null || !viewDTM.isViewDataTypeFromOriginalDTM(dataType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
|
viewDTM.remove(dataType, TaskMonitor.DUMMY);
|
||||||
|
fireTableDataChanged();
|
||||||
|
componentDataChanged();
|
||||||
|
setRelOffsetSelection(offsetSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dataTypeRenamed(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
||||||
|
DataTypePath newPath) {
|
||||||
|
dataTypeMoved(dataTypeManager, oldPath, newPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dataTypeMoved(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
||||||
|
DataTypePath newPath) {
|
||||||
|
|
||||||
|
if (dataTypeManager != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldPath.getDataTypeName().equals(newPath.getDataTypeName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for managed datatype changing
|
||||||
|
DataType originalDt = originalDTM.getDataType(newPath);
|
||||||
|
if (!(originalDt instanceof DatabaseObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DataType dt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(originalDt));
|
||||||
|
if (dt == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
|
try {
|
||||||
|
dt.setName(newPath.getDataTypeName());
|
||||||
|
|
||||||
|
CategoryPath newCategoryPath = newPath.getCategoryPath();
|
||||||
|
CategoryPath oldCategoryPath = oldPath.getCategoryPath();
|
||||||
|
if (!newCategoryPath.equals(oldCategoryPath)) {
|
||||||
|
dt.setCategoryPath(newCategoryPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidNameException | DuplicateNameException e) {
|
||||||
|
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
fireTableDataChanged();
|
||||||
|
componentDataChanged();
|
||||||
|
setRelOffsetSelection(offsetSelection);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeChanged(DataTypeManager dataTypeManager, DataTypePath path) {
|
public void dataTypeChanged(DataTypeManager dataTypeManager, DataTypePath path) {
|
||||||
if (dataTypeManager != originalDTM) {
|
if (dataTypeManager != originalDTM) {
|
||||||
|
@ -1178,65 +1163,25 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DataType dataType = dataTypeManager.getDataType(path);
|
|
||||||
|
DataType changedDt = originalDTM.getDataType(path);
|
||||||
|
if (!(changedDt instanceof DatabaseObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DataType viewDt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(changedDt));
|
||||||
|
if (viewDt == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
adjustComponents(dataType);
|
try {
|
||||||
fireTableDataChanged();
|
viewDTM.replaceDataType(viewDt, changedDt, true);
|
||||||
componentDataChanged();
|
viewComposite.checkForStackGrowth();
|
||||||
setRelOffsetSelection(offsetSelection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeMoved(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
|
||||||
DataTypePath newPath) {
|
|
||||||
if (dataTypeManager != originalDTM) {
|
|
||||||
throw new AssertException("Listener only supports original DTM");
|
|
||||||
}
|
}
|
||||||
if (!isLoaded()) {
|
catch (DataTypeDependencyException e) {
|
||||||
return;
|
throw new AssertException(e);
|
||||||
}
|
}
|
||||||
if (originalDataTypePath != null &&
|
compositeInfoChanged(); // size info may have changed
|
||||||
originalDataTypePath.getDataTypeName().equals(newPath.getDataTypeName()) &&
|
|
||||||
originalDataTypePath.getCategoryPath().equals(oldPath.getCategoryPath())) {
|
|
||||||
originalDataTypePath = newPath;
|
|
||||||
compositeInfoChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeRemoved(DataTypeManager dataTypeManager, DataTypePath path) {
|
|
||||||
if (dataTypeManager != originalDTM) {
|
|
||||||
throw new AssertException("Listener only supports original DTM");
|
|
||||||
}
|
|
||||||
if (!isLoaded()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
|
||||||
DataType dataType = dataTypeManager.getDataType(path);
|
|
||||||
replaceComponents(dataType, DataType.DEFAULT);
|
|
||||||
fireTableDataChanged();
|
|
||||||
componentDataChanged();
|
|
||||||
setRelOffsetSelection(offsetSelection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeRenamed(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
|
||||||
DataTypePath newPath) {
|
|
||||||
if (dataTypeManager != originalDTM) {
|
|
||||||
throw new AssertException("Listener only supports original DTM");
|
|
||||||
}
|
|
||||||
if (!isLoaded()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataTypePath originalPath = getOriginalDataTypePath();
|
|
||||||
if (originalPath == null || !oldPath.equals(originalPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't try to actually rename, since we shouldn't get name change on a
|
|
||||||
// fabricated stack data type.
|
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
setRelOffsetSelection(offsetSelection);
|
setRelOffsetSelection(offsetSelection);
|
||||||
|
@ -1251,9 +1196,21 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DataType oldDataType = viewDTM.getDataType(oldPath);
|
|
||||||
|
DataType dt = viewDTM.getDataType(oldPath);
|
||||||
|
if (dt == null || !viewDTM.isViewDataTypeFromOriginalDTM(dt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
replaceComponents(oldDataType, newDataType);
|
try {
|
||||||
|
viewDTM.replaceDataType(dt, newDataType, true);
|
||||||
|
viewComposite.checkForStackGrowth();
|
||||||
|
}
|
||||||
|
catch (DataTypeDependencyException e) {
|
||||||
|
throw new AssertException(e);
|
||||||
|
}
|
||||||
|
compositeInfoChanged(); // size info may have changed
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
setRelOffsetSelection(offsetSelection);
|
setRelOffsetSelection(offsetSelection);
|
||||||
|
@ -1325,54 +1282,56 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public DataTypeInstance validateComponentDataType(int index, String dtString)
|
// public DataTypeInstance validateComponentDataType(int index, String dtString)
|
||||||
throws CancelledException, UsrException {
|
// throws CancelledException, UsrException {
|
||||||
DataType dt = null;
|
// DataType dt = null;
|
||||||
String dtName = "";
|
// String dtName = "";
|
||||||
dtString = DataTypeHelper.stripWhiteSpace(dtString);
|
// dtString = DataTypeHelper.stripWhiteSpace(dtString);
|
||||||
if (index < getNumComponents()) {
|
// if (index < getNumComponents()) {
|
||||||
DataTypeComponent element = viewComposite.getComponent(index);
|
// DataTypeComponent element = viewComposite.getComponent(index);
|
||||||
dt = element.getDataType();
|
// dt = element.getDataType();
|
||||||
dtName = dt.getDisplayName();
|
// dtName = dt.getDisplayName();
|
||||||
if (dtString.equals(dtName)) {
|
// if (dtString.equals(dtName)) {
|
||||||
return DataTypeInstance.getDataTypeInstance(element.getDataType(),
|
// return DataTypeInstance.getDataTypeInstance(element.getDataType(),
|
||||||
element.getLength(), usesAlignedLengthComponents());
|
// element.getLength(), usesAlignedLengthComponents());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
DataType newDt = DataTypeHelper.parseDataType(index, dtString, this, originalDTM,
|
// DataType newDt = DataTypeHelper.parseDataType(index, dtString, this, originalDTM,
|
||||||
provider.getDtmService());
|
// provider.getDtmService());
|
||||||
|
//
|
||||||
if (newDt == null) {
|
// if (newDt == null) {
|
||||||
if (dt != null) {
|
// if (dt != null) {
|
||||||
throw new UsrException("No data type was specified.");
|
// throw new UsrException("No data type was specified.");
|
||||||
}
|
// }
|
||||||
throw new CancelledException();
|
// throw new CancelledException();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
int newLength = newDt.getLength();
|
// int newLength = newDt.getLength();
|
||||||
|
//
|
||||||
checkIsAllowableDataType(newDt);
|
// checkIsAllowableDataType(newDt);
|
||||||
newDt = resolveDataType(newDt, viewDTM, null);
|
// newDt = resolveDataType(newDt, viewDTM, null);
|
||||||
int maxLength = getMaxReplaceLength(index);
|
// int maxLength = getMaxReplaceLength(index);
|
||||||
if (newLength <= 0) {
|
// if (newLength <= 0) {
|
||||||
throw new UsrException("Can't currently add this data type--not enough space.");
|
// throw new UsrException("Can't currently add this data type--not enough space.");
|
||||||
}
|
// }
|
||||||
if (maxLength > 0 && newLength > maxLength) {
|
// if (maxLength > 0 && newLength > maxLength) {
|
||||||
throw new UsrException(newDt.getDisplayName() + " doesn't fit.");
|
// throw new UsrException(newDt.getDisplayName() + " doesn't fit.");
|
||||||
}
|
// }
|
||||||
return DataTypeInstance.getDataTypeInstance(newDt, newLength,
|
// return DataTypeInstance.getDataTypeInstance(newDt, newLength,
|
||||||
usesAlignedLengthComponents());
|
// usesAlignedLengthComponents());
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deleteComponent(int rowIndex) {
|
protected void deleteComponent(int rowIndex) {
|
||||||
viewComposite.delete(rowIndex);
|
viewComposite.delete(rowIndex);
|
||||||
|
compositeInfoChanged(); // info may have changed
|
||||||
|
fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent getComponent(int rowIndex) {
|
public StackComponentWrapper getComponent(int rowIndex) {
|
||||||
if (viewComposite == null) {
|
if (viewComposite == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,13 @@ import ghidra.app.plugin.core.compositeeditor.*;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
import ghidra.framework.plugintool.Plugin;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
|
||||||
import ghidra.program.model.data.DataTypePath;
|
import ghidra.program.model.data.DataTypePath;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolType;
|
|
||||||
import ghidra.program.util.ProgramChangeRecord;
|
import ghidra.program.util.ProgramChangeRecord;
|
||||||
import ghidra.program.util.ProgramEvent;
|
import ghidra.program.util.ProgramEvent;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.task.SwingUpdateManager;
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor for a Function Stack.
|
* Editor for a Function Stack.
|
||||||
|
@ -45,6 +42,31 @@ public class StackEditorProvider
|
||||||
private Function function;
|
private Function function;
|
||||||
private StackEditorModel stackModel;
|
private StackEditorModel stackModel;
|
||||||
|
|
||||||
|
boolean scheduleRefreshName = false;
|
||||||
|
boolean scheduleReload = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay model update caused by Program change events.
|
||||||
|
*/
|
||||||
|
SwingUpdateManager delayedUpdateMgr = new SwingUpdateManager(200, 200, () -> {
|
||||||
|
try {
|
||||||
|
if (function.isDeleted()) {
|
||||||
|
stackModel.functionChanged(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (scheduleRefreshName) {
|
||||||
|
updateTitle();
|
||||||
|
}
|
||||||
|
if (scheduleReload) {
|
||||||
|
stackModel.functionChanged(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
scheduleRefreshName = false;
|
||||||
|
scheduleReload = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
public StackEditorProvider(Plugin plugin, Function function) {
|
public StackEditorProvider(Plugin plugin, Function function) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
this.program = function.getProgram();
|
this.program = function.getProgram();
|
||||||
|
@ -56,15 +78,22 @@ public class StackEditorProvider
|
||||||
|
|
||||||
initializeActions();
|
initializeActions();
|
||||||
editorPanel = new StackEditorPanel(program, stackModel, this);
|
editorPanel = new StackEditorPanel(program, stackModel, this);
|
||||||
setTitle(getName() + " - " + getProviderSubTitle(function));
|
updateTitle();
|
||||||
plugin.getTool().addComponentProvider(this, true);
|
plugin.getTool().addComponentProvider(this, true);
|
||||||
|
|
||||||
addActionsToTool();
|
addActionsToTool();
|
||||||
editorPanel.getTable().requestFocus();
|
editorPanel.getTable().requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateTitle() {
|
||||||
|
setTabText(function.getName());
|
||||||
|
setTitle(getName() + " - " + getProviderSubTitle(function));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
delayedUpdateMgr.dispose();
|
||||||
program.removeListener(this);
|
program.removeListener(this);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -84,6 +113,11 @@ public class StackEditorProvider
|
||||||
return "Stack Editor";
|
return "Stack Editor";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDisplayName() {
|
||||||
|
return "stack frame: " + function.getName();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpName() {
|
public String getHelpName() {
|
||||||
return "Stack_Editor";
|
return "Stack_Editor";
|
||||||
|
@ -147,32 +181,6 @@ public class StackEditorProvider
|
||||||
return actionMgr.getAllActions();
|
return actionMgr.getAllActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshName() {
|
|
||||||
StackFrameDataType origDt = stackModel.getOriginalComposite();
|
|
||||||
StackFrameDataType viewDt = stackModel.getEditorStack();
|
|
||||||
String oldName = origDt.getName();
|
|
||||||
String newName = function.getName();
|
|
||||||
if (oldName.equals(newName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTitle("Stack Editor: " + newName);
|
|
||||||
try {
|
|
||||||
origDt.setName(newName);
|
|
||||||
if (viewDt.getName().equals(oldName)) {
|
|
||||||
viewDt.setName(newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (InvalidNameException e) {
|
|
||||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
CategoryPath oldCategoryPath = origDt.getCategoryPath();
|
|
||||||
DataTypePath oldDtPath = new DataTypePath(oldCategoryPath, oldName);
|
|
||||||
DataTypePath newDtPath = new DataTypePath(oldCategoryPath, newName);
|
|
||||||
stackModel.dataTypeRenamed(stackModel.getOriginalDataTypeManager(), oldDtPath, newDtPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void domainObjectChanged(DomainObjectChangedEvent event) {
|
public void domainObjectChanged(DomainObjectChangedEvent event) {
|
||||||
if (!isVisible()) {
|
if (!isVisible()) {
|
||||||
|
@ -181,35 +189,40 @@ public class StackEditorProvider
|
||||||
|
|
||||||
int recordCount = event.numRecords();
|
int recordCount = event.numRecords();
|
||||||
for (int i = 0; i < recordCount; i++) {
|
for (int i = 0; i < recordCount; i++) {
|
||||||
|
|
||||||
DomainObjectChangeRecord rec = event.getChangeRecord(i);
|
DomainObjectChangeRecord rec = event.getChangeRecord(i);
|
||||||
EventType eventType = rec.getEventType();
|
EventType eventType = rec.getEventType();
|
||||||
if (eventType == DomainObjectEvent.RESTORED) {
|
|
||||||
refreshName();
|
// NOTE: RESTORED event can be ignored here since the model will be notified
|
||||||
// NOTE: editorPanel should be notified of restored datatype manager via the
|
// of restored datatype manager via the CompositeViewerModel's
|
||||||
// CompositeViewerModel's DataTypeManagerChangeListener restored method
|
// DataTypeManagerChangeListener restored method.
|
||||||
return;
|
|
||||||
|
if (eventType == DomainObjectEvent.FILE_CHANGED) {
|
||||||
|
scheduleRefreshName = true;
|
||||||
|
delayedUpdateMgr.updateLater();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (eventType instanceof ProgramEvent type) {
|
if (eventType instanceof ProgramEvent type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FUNCTION_REMOVED:
|
case FUNCTION_REMOVED:
|
||||||
Function func = (Function) ((ProgramChangeRecord) rec).getObject();
|
Function func = (Function) ((ProgramChangeRecord) rec).getObject();
|
||||||
if (func == function) {
|
if (func == function) {
|
||||||
this.dispose();
|
// Close the Editor.
|
||||||
tool.setStatusInfo("Stack Editor was closed for " + getName());
|
tool.setStatusInfo("Stack Editor was closed for " + getName());
|
||||||
|
dispose();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
case SYMBOL_RENAMED:
|
case SYMBOL_RENAMED:
|
||||||
case SYMBOL_DATA_CHANGED:
|
case SYMBOL_DATA_CHANGED:
|
||||||
Symbol sym = (Symbol) ((ProgramChangeRecord) rec).getObject();
|
Symbol sym = (Symbol) ((ProgramChangeRecord) rec).getObject();
|
||||||
SymbolType symType = sym.getSymbolType();
|
if (sym.isPrimary() && sym.getAddress().equals(function.getEntryPoint())) {
|
||||||
if (symType == SymbolType.LABEL) {
|
scheduleRefreshName = true;
|
||||||
if (sym.isPrimary() &&
|
delayedUpdateMgr.updateLater();
|
||||||
sym.getAddress().equals(function.getEntryPoint())) {
|
|
||||||
refreshName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (inCurrentFunction(rec)) {
|
else if (inCurrentFunction(rec)) {
|
||||||
reloadFunction();
|
scheduleReload = true;
|
||||||
|
delayedUpdateMgr.updateLater();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FUNCTION_CHANGED:
|
case FUNCTION_CHANGED:
|
||||||
|
@ -217,15 +230,15 @@ public class StackEditorProvider
|
||||||
case SYMBOL_REMOVED:
|
case SYMBOL_REMOVED:
|
||||||
case SYMBOL_ADDRESS_CHANGED:
|
case SYMBOL_ADDRESS_CHANGED:
|
||||||
if (inCurrentFunction(rec)) {
|
if (inCurrentFunction(rec)) {
|
||||||
reloadFunction();
|
scheduleReload = true;
|
||||||
|
delayedUpdateMgr.updateLater();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYMBOL_PRIMARY_STATE_CHANGED:
|
case SYMBOL_PRIMARY_STATE_CHANGED:
|
||||||
sym = (Symbol) ((ProgramChangeRecord) rec).getNewValue();
|
sym = (Symbol) ((ProgramChangeRecord) rec).getNewValue();
|
||||||
symType = sym.getSymbolType();
|
if (sym.getAddress().equals(function.getEntryPoint())) {
|
||||||
if (symType == SymbolType.LABEL &&
|
scheduleRefreshName = true;
|
||||||
sym.getAddress().equals(function.getEntryPoint())) {
|
delayedUpdateMgr.updateLater();
|
||||||
refreshName();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -234,16 +247,6 @@ public class StackEditorProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloadFunction() {
|
|
||||||
if (!stackModel.hasChanges()) {
|
|
||||||
stackModel.load(function);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
stackModel.stackChangedExternally(true);
|
|
||||||
editorPanel.setStatus("Stack may have been changed externally--data may be stale.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean inCurrentFunction(DomainObjectChangeRecord record) {
|
private boolean inCurrentFunction(DomainObjectChangeRecord record) {
|
||||||
if (!(record instanceof ProgramChangeRecord)) {
|
if (!(record instanceof ProgramChangeRecord)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,131 +0,0 @@
|
||||||
/* ###
|
|
||||||
* 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.stackeditor;
|
|
||||||
|
|
||||||
import ghidra.docking.settings.Settings;
|
|
||||||
import ghidra.program.model.data.*;
|
|
||||||
import ghidra.program.model.listing.Variable;
|
|
||||||
import ghidra.program.model.listing.VariableStorage;
|
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
|
||||||
import ghidra.program.model.pcode.Varnode;
|
|
||||||
import ghidra.util.InvalidNameException;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
|
||||||
|
|
||||||
public class StackPieceDataType extends DataTypeImpl {
|
|
||||||
|
|
||||||
private final Variable variable;
|
|
||||||
|
|
||||||
StackPieceDataType(Variable var, DataTypeManager dataMgr) {
|
|
||||||
super(CategoryPath.ROOT, getPieceName(var), dataMgr);
|
|
||||||
variable = var;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPieceName(Variable var) {
|
|
||||||
VariableStorage storage = var.getVariableStorage();
|
|
||||||
Varnode stackVarnode = storage.getLastVarnode();
|
|
||||||
int pieceLen = stackVarnode.getSize();
|
|
||||||
return var.getDataType().getName() + ":" + pieceLen + " (piece)";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType clone(DataTypeManager dtm) {
|
|
||||||
if (dtm == getDataTypeManager()) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("May not be cloned with new DataTypeManager");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType copy(DataTypeManager dtm) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setName(String name) throws InvalidNameException {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNameAndCategory(CategoryPath path, String name)
|
|
||||||
throws InvalidNameException, DuplicateNameException {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMnemonic(Settings settings) {
|
|
||||||
DataType dt = variable.getDataType();
|
|
||||||
return dt.getMnemonic(settings) + ":" + getLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLength() {
|
|
||||||
VariableStorage storage = variable.getVariableStorage();
|
|
||||||
Varnode stackVarnode = storage.getLastVarnode();
|
|
||||||
return stackVarnode.getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
// We could provide a description if needed
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEquivalent(DataType dt) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeSizeChanged(DataType dt) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeDeleted(DataType dt) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean dependsOn(DataType dt) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -44,8 +44,6 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito
|
||||||
env.showTool();
|
env.showTool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -140,7 +138,7 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito
|
||||||
Parameter parameter = function.getParameter(parameterIndex);
|
Parameter parameter = function.getParameter(parameterIndex);
|
||||||
SetVariableNameCmd cmd =
|
SetVariableNameCmd cmd =
|
||||||
new SetVariableNameCmd(parameter, newName, SourceType.USER_DEFINED);
|
new SetVariableNameCmd(parameter, newName, SourceType.USER_DEFINED);
|
||||||
applyCmd(program, cmd);
|
program.withTransaction("Rename Parameter", () -> cmd.applyTo(program)); // avoid blocking
|
||||||
return parameter;
|
return parameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -384,11 +384,29 @@ public class StackEditorCellEditTest extends AbstractStackEditorTest {
|
||||||
typeInCellEditor("testName1\n");
|
typeInCellEditor("testName1\n");
|
||||||
assertTrue(applyAction.isEnabled());
|
assertTrue(applyAction.isEnabled());
|
||||||
|
|
||||||
// Change name back and apply disables
|
// Attempt use of another default name
|
||||||
|
clickTableCell(getTable(), 0, colNum, 2);
|
||||||
|
assertIsEditingField(0, colNum);
|
||||||
|
selectAllInCellEditor();
|
||||||
|
typeInCellEditor("local_8\n");
|
||||||
|
assertStatus("Cannot set a stack variable name to a default value");
|
||||||
|
assertCellString("testName1", 0, colNum);
|
||||||
|
assertTrue(applyAction.isEnabled());
|
||||||
|
|
||||||
|
// Change name back to original and apply disables
|
||||||
clickTableCell(getTable(), 0, colNum, 2);
|
clickTableCell(getTable(), 0, colNum, 2);
|
||||||
assertIsEditingField(0, colNum);
|
assertIsEditingField(0, colNum);
|
||||||
selectAllInCellEditor();
|
selectAllInCellEditor();
|
||||||
typeInCellEditor("local_10\n");
|
typeInCellEditor("local_10\n");
|
||||||
|
assertCellString("local_10", 0, colNum);
|
||||||
|
assertTrue(!applyAction.isEnabled());
|
||||||
|
|
||||||
|
// Change name back to original and apply disables
|
||||||
|
clickTableCell(getTable(), 0, colNum, 2);
|
||||||
|
assertIsEditingField(0, colNum);
|
||||||
|
selectAllInCellEditor();
|
||||||
|
typeInCellEditor("\b\n"); // clear entry
|
||||||
|
assertCellString("local_10", 0, colNum);
|
||||||
assertTrue(!applyAction.isEnabled());
|
assertTrue(!applyAction.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -200,7 +200,7 @@ public class StackEditorEnablementTest extends AbstractStackEditorTest {
|
||||||
public void testCentralComponentSelectedEnablement() throws Exception {
|
public void testCentralComponentSelectedEnablement() throws Exception {
|
||||||
init(SIMPLE_STACK);
|
init(SIMPLE_STACK);
|
||||||
|
|
||||||
// Check enablement on central component selected.
|
// Check enablement on central defined-component selected which has undefined datatype
|
||||||
|
|
||||||
runSwing(() -> model.setSelection(new int[] { 1 }));
|
runSwing(() -> model.setSelection(new int[] { 1 }));
|
||||||
int numBytes = getModel().getMaxReplaceLength(1);
|
int numBytes = getModel().getMaxReplaceLength(1);
|
||||||
|
|
|
@ -19,8 +19,7 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
|
||||||
import javax.swing.JTextField;
|
import javax.swing.*;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -324,6 +323,8 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||||
int parameterIndex = 0;
|
int parameterIndex = 0;
|
||||||
Parameter parameter = renameParameterInListing(parameterIndex, "listing.test.name");
|
Parameter parameter = renameParameterInListing(parameterIndex, "listing.test.name");
|
||||||
|
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
// Verify the provider's name for that parameter is updated
|
// Verify the provider's name for that parameter is updated
|
||||||
String modelParameterName = getParameterNameFromModel(parameterIndex);
|
String modelParameterName = getParameterNameFromModel(parameterIndex);
|
||||||
assertEquals(parameter.getName(), modelParameterName);
|
assertEquals(parameter.getName(), modelParameterName);
|
||||||
|
@ -342,6 +343,9 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||||
// Change the name of a parameter in the Listing
|
// Change the name of a parameter in the Listing
|
||||||
renameParameterInListing(parameterIndex, "listing.test.name");
|
renameParameterInListing(parameterIndex, "listing.test.name");
|
||||||
|
|
||||||
|
JDialog reloadDialog = waitForJDialog("Reload Stack Editor?");
|
||||||
|
pressButton(reloadDialog, "No");
|
||||||
|
|
||||||
// Verify the name of the parameter in the provider is not changed from the original edit
|
// Verify the name of the parameter in the provider is not changed from the original edit
|
||||||
String currentModelName = getParameterNameFromModel(parameterIndex);
|
String currentModelName = getParameterNameFromModel(parameterIndex);
|
||||||
assertEquals(newModelName, currentModelName);
|
assertEquals(newModelName, currentModelName);
|
||||||
|
@ -360,6 +364,9 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||||
// Change the name of a parameter in the Listing
|
// Change the name of a parameter in the Listing
|
||||||
renameParameterInListing(parameterIndex, "listing.test.name");
|
renameParameterInListing(parameterIndex, "listing.test.name");
|
||||||
|
|
||||||
|
JDialog reloadDialog = waitForJDialog("Reload Stack Editor?");
|
||||||
|
pressButton(reloadDialog, "No");
|
||||||
|
|
||||||
// Press Apply
|
// Press Apply
|
||||||
apply();
|
apply();
|
||||||
|
|
||||||
|
@ -386,6 +393,9 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||||
String newListingText = "listing.test.name";
|
String newListingText = "listing.test.name";
|
||||||
renameParameterInListing(parameterIndex, newListingText);
|
renameParameterInListing(parameterIndex, newListingText);
|
||||||
|
|
||||||
|
JDialog reloadDialog = waitForJDialog("Reload Stack Editor?");
|
||||||
|
pressButton(reloadDialog, "No");
|
||||||
|
|
||||||
// Press Apply
|
// Press Apply
|
||||||
apply();
|
apply();
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||||
private final ComponentDBAdapter adapter;
|
private final ComponentDBAdapter adapter;
|
||||||
private final DBRecord record; // null record -> immutable component
|
private final DBRecord record; // null record -> immutable component
|
||||||
private final CompositeDB parent;
|
private final CompositeDB parent;
|
||||||
|
private final DataType cachedDataType; // used by immutable defined component (no record)
|
||||||
private DataType cachedDataType; // required for bit-fields during packing process
|
|
||||||
|
|
||||||
private int ordinal;
|
private int ordinal;
|
||||||
private int offset;
|
private int offset;
|
||||||
|
@ -56,9 +55,15 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||||
*/
|
*/
|
||||||
DataTypeComponentDB(DataTypeManagerDB dataMgr, CompositeDB parent, int ordinal, int offset,
|
DataTypeComponentDB(DataTypeManagerDB dataMgr, CompositeDB parent, int ordinal, int offset,
|
||||||
DataType datatype, int length) {
|
DataType datatype, int length) {
|
||||||
this(dataMgr, parent, ordinal, offset);
|
this.dataMgr = dataMgr;
|
||||||
|
this.parent = parent;
|
||||||
this.cachedDataType = datatype;
|
this.cachedDataType = datatype;
|
||||||
|
|
||||||
|
this.ordinal = ordinal;
|
||||||
|
this.offset = offset;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
|
this.record = null;
|
||||||
|
this.adapter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +78,8 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||||
this.dataMgr = dataMgr;
|
this.dataMgr = dataMgr;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.ordinal = ordinal;
|
this.ordinal = ordinal;
|
||||||
|
this.cachedDataType = null;
|
||||||
|
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
this.length = 1;
|
this.length = 1;
|
||||||
this.record = null;
|
this.record = null;
|
||||||
|
@ -90,11 +97,13 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||||
DBRecord record) {
|
DBRecord record) {
|
||||||
this.dataMgr = dataMgr;
|
this.dataMgr = dataMgr;
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
|
this.cachedDataType = null;
|
||||||
this.record = record;
|
this.record = record;
|
||||||
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
ordinal = record.getIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL);
|
this.ordinal = record.getIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL);
|
||||||
offset = record.getIntValue(ComponentDBAdapter.COMPONENT_OFFSET_COL);
|
this.offset = record.getIntValue(ComponentDBAdapter.COMPONENT_OFFSET_COL);
|
||||||
length = record.getIntValue(ComponentDBAdapter.COMPONENT_SIZE_COL);
|
this.length = record.getIntValue(ComponentDBAdapter.COMPONENT_SIZE_COL);
|
||||||
if (isZeroBitFieldComponent()) {
|
if (isZeroBitFieldComponent()) {
|
||||||
length = 0; // previously stored as 1, force to 0
|
length = 0; // previously stored as 1, force to 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1378,11 +1378,13 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||||
* @param componentName name of component replacement (may be null)
|
* @param componentName name of component replacement (may be null)
|
||||||
* @param comment comment for component replacement (may be null)
|
* @param comment comment for component replacement (may be null)
|
||||||
* @return new/updated component (may be null if replacement is not a defined component)
|
* @return new/updated component (may be null if replacement is not a defined component)
|
||||||
|
* @throws IllegalArgumentException if unable to identify/make sufficient space
|
||||||
* @throws IOException if an IO error occurs
|
* @throws IOException if an IO error occurs
|
||||||
*/
|
*/
|
||||||
private DataTypeComponent doComponentReplacement(
|
private DataTypeComponent doComponentReplacement(
|
||||||
LinkedList<DataTypeComponentDB> replacedComponents, int offset, DataType dataType,
|
LinkedList<DataTypeComponentDB> replacedComponents, int offset, DataType dataType,
|
||||||
int length, String componentName, String comment) throws IOException {
|
int length, String componentName, String comment)
|
||||||
|
throws IllegalArgumentException, IOException {
|
||||||
|
|
||||||
// Attempt quick update of a single defined component if possible.
|
// Attempt quick update of a single defined component if possible.
|
||||||
// A quick update requires that component characteristics including length, offset,
|
// A quick update requires that component characteristics including length, offset,
|
||||||
|
@ -1416,13 +1418,14 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final DataTypeComponent replace(int ordinal, DataType dataType, int length)
|
public final DataTypeComponent replace(int ordinal, DataType dataType, int length)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException, IndexOutOfBoundsException {
|
||||||
return replace(ordinal, dataType, length, null, null);
|
return replace(ordinal, dataType, length, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent replace(int ordinal, DataType dataType, int length,
|
public DataTypeComponent replace(int ordinal, DataType dataType, int length,
|
||||||
String componentName, String comment) {
|
String componentName, String comment)
|
||||||
|
throws IllegalArgumentException, IndexOutOfBoundsException {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkDeleted();
|
checkDeleted();
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -277,16 +277,18 @@ class FunctionStackFrame implements StackFrame {
|
||||||
function.setLocalSize(size);
|
function.setLocalSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see ghidra.program.model.listing.StackFrame#getParameterSize()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int getParameterSize() {
|
public int getParameterSize() {
|
||||||
function.manager.lock.acquire();
|
function.manager.lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
|
|
||||||
|
// NOTE: This logic is sensitive to the existance of Local variables at the incorrect
|
||||||
|
// stack offset placed before parameters. This can occur when adjustments are made to
|
||||||
|
// the prototype model's stack pentry specification. Unfortunately, the distinction
|
||||||
|
// between a parameter and a local is locked-in at the time of creation due to the
|
||||||
|
// use of distinct symbol types.
|
||||||
|
|
||||||
int baseOffset = 0;
|
int baseOffset = 0;
|
||||||
Integer base = VariableUtilities.getBaseStackParamOffset(function);
|
Integer base = VariableUtilities.getBaseStackParamOffset(function);
|
||||||
if (base != null) {
|
if (base != null) {
|
||||||
|
|
|
@ -44,7 +44,8 @@ public interface Structure extends Composite {
|
||||||
public DataTypeComponent getComponent(int ordinal) throws IndexOutOfBoundsException;
|
public DataTypeComponent getComponent(int ordinal) throws IndexOutOfBoundsException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first defined component located at or after the specified offset.
|
* Gets the first defined component located at or after the specified offset. If a
|
||||||
|
* component contains the specified offset that component will be returned.
|
||||||
* Note: The returned component may be a zero-length component.
|
* Note: The returned component may be a zero-length component.
|
||||||
*
|
*
|
||||||
* @param offset the byte offset into this structure
|
* @param offset the byte offset into this structure
|
||||||
|
@ -436,7 +437,7 @@ public interface Structure extends Composite {
|
||||||
* @throws IllegalArgumentException if amount < 0
|
* @throws IllegalArgumentException if amount < 0
|
||||||
*/
|
*/
|
||||||
public void growStructure(int amount);
|
public void growStructure(int amount);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the size of the structure to the specified byte-length. If the length is shortened defined
|
* 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.
|
* components will be cleared and removed as required.
|
||||||
|
|
|
@ -107,13 +107,6 @@ public interface StackFrame {
|
||||||
*/
|
*/
|
||||||
public int getParameterOffset();
|
public int getParameterOffset();
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Set the offset on the stack of the parameters.
|
|
||||||
// *
|
|
||||||
// * @param offset the start offset of parameters on the stack
|
|
||||||
// */
|
|
||||||
// public void setParameterOffset(int offset) throws InvalidInputException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if specified offset could correspond to a parameter
|
* Returns true if specified offset could correspond to a parameter
|
||||||
* @param offset
|
* @param offset
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue