diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/RenameDataFieldCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/RenameDataFieldCmd.java index 9c7bdec584..3746954470 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/RenameDataFieldCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/data/RenameDataFieldCmd.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,13 +15,14 @@ */ package ghidra.app.cmd.data; +import java.util.Objects; + import ghidra.framework.cmd.Command; -import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.data.*; import ghidra.program.model.listing.Program; -import ghidra.util.exception.DuplicateNameException; /** - * Command to rename a component in a data type. + * Command to rename a component in a {@link Composite} data type. * */ public class RenameDataFieldCmd implements Command { @@ -47,20 +48,20 @@ public class RenameDataFieldCmd implements Command { statusMsg = "Null data type"; return false; } - try { - comp.setFieldName(newName); - return true; + + String name = InternalDataTypeComponent.cleanupFieldName(newName); + + if (!Objects.equals(name, comp.getFieldName())) { + comp = comp.setFieldName(newName); + if (!Objects.equals(name, comp.getFieldName())) { + statusMsg = "Unable to rename component"; + return false; + } } - catch (DuplicateNameException e) { - statusMsg = "Type name already exists: " + newName; - } - return false; + + return true; } - /* - * (non-Javadoc) - * @see ghidra.framework.cmd.Command#getStatusMsg() - */ @Override public String getStatusMsg() { return statusMsg; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java index 56e3868fce..aafe6c4d5c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java @@ -802,13 +802,9 @@ public abstract class CompEditorModel extends CompositeEdit DataTypeComponent dtc = getComponent(startRowIndex); // Set the field name and comment the same as before - try { - dtc.setFieldName(oldDtc.getFieldName()); - } - catch (DuplicateNameException e) { - Msg.showError(this, null, "Unexcected Exception", "Exception applying field name", e); - } + dtc.setFieldName(oldDtc.getFieldName()); dtc.setComment(oldDtc.getComment()); + fixSelection(); selectionChanged(); return dtc; @@ -1165,32 +1161,32 @@ public abstract class CompEditorModel extends CompositeEdit } } - @Override - public void validateComponentName(int rowIndex, String name) throws UsrException { - if (nameExistsElsewhere(name, rowIndex)) { - throw new InvalidNameException("Name \"" + name + "\" already exists."); - } - } - @Override public boolean setComponentName(int rowIndex, String name) throws InvalidNameException { - String oldName = getComponent(rowIndex).getFieldName(); - if (Objects.equals(oldName, name)) { + name = InternalDataTypeComponent.cleanupFieldName(name); // will trim name if needed + DataTypeComponent component = getComponent(rowIndex); + if (Objects.equals(name, component.getDefaultFieldName())) { + name = null; + } + if (Objects.equals(name, component.getFieldName())) { return false; } - if (nameExistsElsewhere(name, rowIndex)) { - throw new InvalidNameException("Name \"" + name + "\" already exists."); + if (viewComposite.findComponent(name) != null) { + // Warn user and confirm rename when duplicate name is used + if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialog(null, + "Duplicate Field Name", + "Duplicate field name. Proceed with rename?", + "Rename!", OptionDialog.WARNING_MESSAGE)) { + return false; + } } - return viewDTM.withTransaction("Set Component Name", () -> { - try { - getComponent(rowIndex).setFieldName(name); // setFieldName handles trimming - return true; - } - catch (DuplicateNameException exc) { - throw new InvalidNameException(exc.getMessage()); - } + + String newName = name; + return viewDTM.withTransaction("Set Field Name", () -> { + getComponent(rowIndex).setFieldName(newName); + return true; }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java index 78c09ae685..189c4084c7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java @@ -1097,36 +1097,6 @@ abstract public class CompositeEditorModel extends Composit return null; } - /** - * Check for any data member in the composite with the specified name - * other than the component at the specified index. - * - * @param name the component name to look for. - * @param rowIndex index of the row (component). - * - * @return true if the name exists elsewhere. - */ - protected boolean nameExistsElsewhere(String name, int rowIndex) { - if (name != null) { - name = name.trim(); - if (name.length() == 0) { - return false; - } - int numComponents = getNumComponents(); - for (int i = 0; i < rowIndex && i < numComponents; i++) { - if (name.equals(getComponent(i).getFieldName())) { - return true; - } - } - for (int i = rowIndex + 1; i < numComponents; i++) { - if (name.equals(getComponent(i).getFieldName())) { - return true; - } - } - } - return false; - } - /** * Determine if the data type is a valid one to place into the current structure being edited. * If invalid, an exception will be thrown. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index 3e946e49a0..72d9fb9b50 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -1145,8 +1145,8 @@ public abstract class CompositeEditorPanel { DataTypeComponent comp = getComponent(startRowIndex); // Set the field name and comment the same as before - try { - comp.setFieldName(fieldName); - } - catch (DuplicateNameException exc) { - Msg.showError(this, null, null, null); - } + comp.setFieldName(fieldName); comp.setComment(comment); // Create any needed undefined data types. @@ -1377,13 +1372,8 @@ class StructureEditorModel extends CompEditorModel { DataTypeComponent comp = getComponent(rowIndex); // Set the field name and comment the same as before if unspecified - try { - if (comp.getFieldName() == null) { - comp.setFieldName(fieldName); - } - } - catch (DuplicateNameException exc) { - Msg.showError(this, null, null, null); + if (comp.getFieldName() == null) { + comp.setFieldName(fieldName); } if (StringUtils.isBlank(comp.getComment())) { comp.setComment(comment); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/EditDataFieldDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/EditDataFieldDialog.java index 52c1f39dda..fccf82ca8a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/EditDataFieldDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/EditDataFieldDialog.java @@ -19,12 +19,14 @@ import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.util.Date; +import java.util.Objects; import javax.swing.*; import org.apache.commons.lang3.StringUtils; import docking.DialogComponentProvider; +import docking.widgets.OptionDialog; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.datatype.DataTypeSelectionEditor; import ghidra.framework.cmd.Command; @@ -439,9 +441,8 @@ public class EditDataFieldDialog extends DialogComponentProvider { // replace that default type with a type that will force a record to be get created. // We need a record to exist in order to set a comment or name. DataType newtype = new Undefined1DataType(); - DataTypeComponent newDtc = - struct.replaceAtOffset(dtc.getOffset(), newtype, 1, "tempName", - "Created by Edit Data Field action"); + DataTypeComponent newDtc = struct.replaceAtOffset(dtc.getOffset(), newtype, 1, + "tempName", "Created by Edit Data Field action"); DataType oldDt = dtc.getDataType(); DataType editorDt = dataTypeEditor.getCellEditorValueAsDataType(); @@ -459,15 +460,28 @@ public class EditDataFieldDialog extends DialogComponentProvider { return true; } + String newName = InternalDataTypeComponent.cleanupFieldName(getNewFieldName()); DataTypeComponent dtc = composite.getComponent(ordinal); - try { - dtc.setFieldName(getNewFieldName()); + if (Objects.equals(newName, dtc.getDefaultFieldName())) { + newName = null; + } + if (Objects.equals(newName, dtc.getFieldName())) { return true; } - catch (DuplicateNameException e) { - statusMessage = "Duplicate field name"; - return false; + + if (newName != null && composite.findComponent(newName) != null) { + + // Warn user and confirm rename when duplicate name is used + if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialog(getComponent(), + "Duplicate Field Name", + "Duplicate field name. Proceed with rename?", + "Rename!", OptionDialog.WARNING_MESSAGE)) { + return false; + } } + + dtc.setFieldName(newName); + return true; } private boolean updateComment() { @@ -512,8 +526,7 @@ public class EditDataFieldDialog extends DialogComponentProvider { return; } - DataTypeInstance dti = - DataTypeInstance.getDataTypeInstance(resolvedDt, -1, false); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(resolvedDt, -1, false); DataType dataType = dti.getDataType(); int length = dti.getLength(); String fieldName = dtc.getFieldName(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java index 8b11872c9b..d3358b7694 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java @@ -40,7 +40,6 @@ import ghidra.program.database.DatabaseObject; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.SymbolUtilities; import ghidra.util.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; @@ -707,10 +706,7 @@ public class StackEditorModel extends CompositeEditorModel { @Override public void validateComponentName(int currentIndex, String name) throws UsrException { - if (SymbolUtilities.containsInvalidChars(name)) { - throw new InvalidInputException( - "Symbol name \"" + name + "\"contains invalid characters."); - } + viewComposite.checkNameChange(currentIndex, name); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java index 69b10363fe..8769211e4d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java @@ -31,9 +31,11 @@ import ghidra.program.model.lang.ProgramArchitecture; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.symbol.SymbolTable; import ghidra.program.model.symbol.SymbolUtilities; import ghidra.util.*; -import ghidra.util.exception.*; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.InvalidInputException; /** * {@link StackFrameDataType} provides a {@link Structure} representation of a {@link StackFrame} @@ -419,19 +421,15 @@ class StackFrameDataType implements Structure { * @param name the new name. Null indicates the default name. * @return true if name change was successful, else false * @throws IndexOutOfBoundsException if specified ordinal is out of range - * @throws IllegalArgumentException if name is invalid + * @throws InvalidNameException if an invalid or duplicate name is specified */ - public boolean setName(int ordinal, String name) throws IndexOutOfBoundsException { + public boolean setName(int ordinal, String name) + throws IndexOutOfBoundsException, InvalidNameException { StackComponentWrapper comp = getComponent(ordinal); String fieldName = comp.getFieldName(); - if (name != null) { - name = name.trim(); - if (name.length() == 0 || isDefaultName(name)) { - name = null; - } - } + name = checkNameChange(ordinal, name); if (SystemUtilities.isEqual(name, fieldName)) { return false; @@ -445,17 +443,53 @@ class StackFrameDataType implements Structure { comp = replace(comp.getOrdinal(), DataType.DEFAULT, 1, name, null); } else { - try { - comp.dtc.setFieldName(name); - } - catch (DuplicateNameException e) { - // FIXME: Inconsistent API / how should names be validated and on which methods? - return false; - } + comp.dtc.setFieldName(name); } return true; } + /** + * Preliminary check if a component may be renamed to the specified name. + * + * @param ordinal the ordinal + * @param name the new name. Null indicates the default name. + * @return name which will actually be applied after cleaning + * @throws IndexOutOfBoundsException if specified ordinal is out of range + * @throws InvalidNameException if an invalid or duplicate name is specified + */ + public String checkNameChange(int ordinal, String name) throws InvalidNameException { + if (name != null) { + name = name.trim(); + if (name.length() == 0 || isDefaultName(name)) { + name = null; + } + } + + if (name != null) { + try { + SymbolUtilities.validateName(name); + } + catch (InvalidInputException e) { + throw new InvalidNameException(e.getMessage()); + } + } + + StackComponentWrapper comp = getComponent(ordinal); + String oldFieldName = comp.getFieldName(); + if (SystemUtilities.isEqual(name, oldFieldName)) { + return oldFieldName; + } + + SymbolTable symbolTable = function.getProgram().getSymbolTable(); + if (name != null && (wrappedStruct.findComponent(name) != null || + !symbolTable.getSymbols(name, function).isEmpty())) { + // Stack or symbol table storage has a conflicting variable or symbol with the same name + throw new InvalidNameException("Name conflicts with another variable: " + name); + } + + return name; + } + /** * Sets the comment at the specified ordinal. * @@ -834,7 +868,7 @@ class StackFrameDataType implements Structure { * Unsupported method. Must use {@link StackFrameDataType#setComment(int, String)}. */ @Override - public void setComment(String comment) { + public DataTypeComponent setComment(String comment) { throw new UnsupportedOperationException(); } @@ -920,7 +954,7 @@ class StackFrameDataType implements Structure { * Unsupported method. Must use {@link StackFrameDataType#setName(int, String)}. */ @Override - public void setFieldName(String fieldName) throws DuplicateNameException { + public DataTypeComponent setFieldName(String fieldName) { throw new UnsupportedOperationException(); } @@ -1070,6 +1104,11 @@ class StackFrameDataType implements Structure { return new StackComponentWrapper(dtc); } + @Override + public DataTypeComponent findComponent(String name) { + throw new UnsupportedOperationException(); + } + @Override public void clearComponent(int ordinal) throws IndexOutOfBoundsException { wrappedStruct.clearComponent(ordinal); @@ -1193,6 +1232,19 @@ class StackFrameDataType implements Structure { name = null; } + if (name != null) { + try { + SymbolUtilities.validateName(name); + } + catch (InvalidInputException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + // NOTE: We don't check for duplicate name since this method is intended for stack + // frame internal use only where any required conflict check should already have been + // performed + DataTypeComponent dtc = wrappedStruct.replace(ordinal, dataType, length, name, comment); checkForStackGrowth(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java index fb4036c8a3..3845e994e6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/EditFieldNameDialog.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,18 +17,18 @@ package ghidra.app.util; import java.awt.BorderLayout; import java.awt.Dimension; +import java.util.Objects; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.border.TitledBorder; import docking.DialogComponentProvider; +import docking.widgets.OptionDialog; import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; +import ghidra.program.model.data.*; import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; -import ghidra.util.exception.DuplicateNameException; public class EditFieldNameDialog extends DialogComponentProvider { @@ -77,36 +77,39 @@ public class EditFieldNameDialog extends DialogComponentProvider { @Override protected void okCallback() { - String newName = fieldName.getText().trim(); - - if (newName.equals(getCurrentFieldName())) { + String newName = InternalDataTypeComponent.cleanupFieldName(fieldName.getText()); + if (Objects.equals(newName, dtComp.getDefaultFieldName())) { + newName = null; + } + if (Objects.equals(newName, dtComp.getFieldName())) { close(); return; } - boolean success = false; + DataType parent = dtComp.getParent(); + if (newName != null && parent instanceof Composite composite && + composite.findComponent(newName) != null) { + + // Warn user and confirm rename when duplicate name is used + if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialog(getComponent(), + "Duplicate Field Name", + "Duplicate field name. Proceed with rename?", + "Rename!", OptionDialog.WARNING_MESSAGE)) { + return; + } + } + int txId = program.startTransaction("Edit Field Name"); try { dtComp.setFieldName(newName); - DataType parent = dtComp.getParent(); - if (parent != null) { - long timeNow = System.currentTimeMillis(); - parent.setLastChangeTime(timeNow); - } - success = true; - } - catch (DuplicateNameException e) { - setStatusText(e.getMessage()); } finally { program.endTransaction(txId, true); } - if (success) { - dtComp = null; - program = null; - close(); - } + dtComp = null; + program = null; + close(); } public void editField(DataTypeComponent dataTypeComponent, Program p) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java index 4fd4fcc80e..f9322050c4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestAbstractControlBlock.java @@ -23,7 +23,6 @@ import ghidra.docking.settings.SettingsImpl; import ghidra.pcode.emu.PcodeThread; import ghidra.pcode.exec.PcodeArithmetic.Purpose; import ghidra.pcode.exec.PcodeExecutorState; -import ghidra.pcode.memstate.MemoryState; import ghidra.pcode.utils.Utils; import ghidra.program.disassemble.Disassembler; import ghidra.program.model.address.*; @@ -296,10 +295,9 @@ public abstract class PCodeTestAbstractControlBlock { } protected int getStructureComponent(Structure testInfoStruct, String fieldName) { - for (DataTypeComponent component : testInfoStruct.getDefinedComponents()) { - if (fieldName.equals(component.getFieldName())) { - return component.getOffset(); - } + DataTypeComponent component = testInfoStruct.findComponent(fieldName); + if (component != null) { + return component.getOffset(); } throw new RuntimeException(fieldName + " field not found within " + testInfoStruct.getName() + " structure definition at " + infoStructAddr.toString(true)); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java index 173031997f..5c4f8f3af3 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java @@ -932,13 +932,8 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); - try { - DataTypeComponent dtc = s.getComponent(0); - dtc.setFieldName("Field One"); - } - catch (DuplicateNameException e) { - Assert.fail("Got duplicate name exception!"); - } + DataTypeComponent dtc = s.getComponent(0); + dtc.setFieldName("Field One"); } @Override @@ -950,14 +945,9 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); - try { - DataTypeComponent dtc = s.getComponent(2); - dtc.setFieldName("My Field Three"); - dtc.setComment("my comments for Field 3"); - } - catch (DuplicateNameException e) { - Assert.fail("Got duplicate name exception!"); - } + DataTypeComponent dtc = s.getComponent(2); + dtc.setFieldName("My Field Three"); + dtc.setComment("my comments for Field 3"); } }); executeMerge(DataTypeMergeManager.OPTION_MY); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java index 4c147c79b6..d372e5dc33 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java @@ -23,7 +23,6 @@ import org.junit.Test; import ghidra.program.database.*; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; -import ghidra.util.exception.DuplicateNameException; /** * More data type merge tests. @@ -122,17 +121,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - Union union = (Union) dt; - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Union union = (Union) dt; + union.add(new FloatDataType(), "Float Field", "my comments"); + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); } }); executeMerge(); @@ -190,17 +182,11 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - Union union = (Union) dt; - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Union union = (Union) dt; + union.add(new FloatDataType(), "Float Field", "my comments"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); } }); executeMerge(); @@ -1209,26 +1195,18 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - Union union = (Union) dt; - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_DLL_Table", s); - Pointer p = PointerDataType.getPointer(td, 4); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(p); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Union union = (Union) dt; + union.add(new FloatDataType(), "Float Field", "my comments"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + TypeDef td = new TypedefDataType(new CategoryPath("/Category1"), "TD_DLL_Table", s); + Pointer p = PointerDataType.getPointer(td, 4); + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(p); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1287,23 +1265,16 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - Union union = (Union) dt; - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Union union = (Union) dt; + union.add(new FloatDataType(), "Float Field", "my comments"); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1375,28 +1346,20 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - union.add(enumm); + union.add(new FloatDataType(), "Float Field", "my comments"); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + union.add(enumm); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1447,28 +1410,21 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - union.add(enumm); + union.add(new FloatDataType(), "Float Field", "my comments"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + union.add(enumm); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1529,28 +1485,21 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - union.add(enumm); + union.add(new FloatDataType(), "Float Field", "my comments"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + union.add(enumm); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1601,30 +1550,23 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm); - union.add(td); + union.add(new FloatDataType(), "Float Field", "my comments"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm); + union.add(td); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1704,33 +1646,26 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm); - Pointer p = PointerDataType.getPointer(td, 4);// TD_MyEnum * - p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * - p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * * - union.add(p); + union.add(new FloatDataType(), "Float Field", "my comments"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm); + Pointer p = PointerDataType.getPointer(td, 4);// TD_MyEnum * + p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * + p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * * + union.add(p); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1790,37 +1725,29 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm); - Pointer p = PointerDataType.getPointer(td, 4);// TD_MyEnum * - p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * - p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * * + union.add(new FloatDataType(), "Float Field", "my comments"); - // create an array of TD_MyEnum * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - dtc = union.add(array); - dtc.setComment("an array"); - dtc.setFieldName("array field name"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm); + Pointer p = PointerDataType.getPointer(td, 4);// TD_MyEnum * + p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * + p = PointerDataType.getPointer(p, 4);// TD_MyEnum * * * - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + // create an array of TD_MyEnum * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + union.add(array, "array field name", "an array"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java index 85d032d1b9..665bc2c8d5 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge5Test.java @@ -59,29 +59,20 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); + union.add(new FloatDataType(), "Float Field", "my comments"); - TypeDef td = new TypedefDataType(new CategoryPath("/Category1"), "TD_Default", - DataType.DEFAULT); + TypeDef td = new TypedefDataType(new CategoryPath("/Category1"), "TD_Default", + DataType.DEFAULT); - dtc = union.add(td); - dtc.setComment("a typedef"); - dtc.setFieldName("typedef field name TD_Default"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + union.add(td, "typedef field name TD_Default", "a typedef"); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -137,42 +128,33 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); - Pointer p = PointerDataType.getPointer(enumm, 4);// MyEnum * - p = PointerDataType.getPointer(p, 4);// MyEnum * * - p = PointerDataType.getPointer(p, 4);// MyEnum * * * - p = PointerDataType.getPointer(p, 4);// MyEnum * * * * - p = PointerDataType.getPointer(p, 4);// MyEnum * * * * * + union.add(new FloatDataType(), "Float Field", "my comments"); - // create an array of MyEnum * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + Pointer p = PointerDataType.getPointer(enumm, 4);// MyEnum * + p = PointerDataType.getPointer(p, 4);// MyEnum * * + p = PointerDataType.getPointer(p, 4);// MyEnum * * * + p = PointerDataType.getPointer(p, 4);// MyEnum * * * * + p = PointerDataType.getPointer(p, 4);// MyEnum * * * * * - TypeDef td = new TypedefDataType(new CategoryPath("/Category1"), - "TD_MyEnumPointer", array); + // create an array of MyEnum * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); - dtc = union.add(td); - dtc.setComment("a typedef"); - dtc.setFieldName("typedef field name TD_MyEnumPointer"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", array); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); + union.add(td, "typedef field name TD_MyEnumPointer", "a typedef"); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -238,45 +220,37 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); - enumm.add("one", 1); - enumm.add("two", 2); - enumm.add("three", 3); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "MyEnum", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); - Pointer p = PointerDataType.getPointer(enumm, 4);// MyEnum * - p = PointerDataType.getPointer(p, 4);// MyEnum * * - p = PointerDataType.getPointer(p, 4);// MyEnum * * * - p = PointerDataType.getPointer(p, 4);// MyEnum * * * * - p = PointerDataType.getPointer(p, 4);// MyEnum * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of MyEnum * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// MyEnum * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// MyEnum * + p = PointerDataType.getPointer(p, 4);// MyEnum * * + p = PointerDataType.getPointer(p, 4);// MyEnum * * * + p = PointerDataType.getPointer(p, 4);// MyEnum * * * * + p = PointerDataType.getPointer(p, 4);// MyEnum * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + // create an array of MyEnum * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// MyEnum * * * * *[5] * - dtc = union.add(td); - dtc.setComment("a typedef"); - dtc.setFieldName("typedef field name TD_MyEnumPointer"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + union.add(td, "typedef field name TD_MyEnumPointer", "a typedef"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -353,47 +327,37 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - dtc = union.add(td); - dtc.setComment("a typedef"); - dtc.setFieldName("typedef field name TD_MyEnumPointer"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); + union.add(td, "typedef field name TD_MyEnumPointer", "a typedef"); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -474,46 +438,37 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - dtc = union.add(td); - dtc.setComment("a typedef"); - dtc.setFieldName("typedef field name TD_MyEnumPointer"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + union.add(td, "typedef field name TD_MyEnumPointer", "a typedef"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -594,46 +549,37 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - dtc = union.add(td); - dtc.setComment("a typedef"); - dtc.setFieldName("typedef field name TD_MyEnumPointer"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + union.add(td, "typedef field name TD_MyEnumPointer", "a typedef"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -727,46 +673,37 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * - dtc = union.add(p); - dtc.setComment("a pointer to a typedef"); - dtc.setFieldName("typedef field name TD_MyEnumPointer *"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * + union.add(p, "typedef field name TD_MyEnumPointer *", "a pointer to a typedef"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -851,49 +788,40 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - // create a TypeDef on p - td = new TypedefDataType(new CategoryPath("/Category1"), "TD_on_Pointer", p); - dtc = union.add(td); - dtc.setFieldName("typedef field name"); - dtc.setComment("a typedef on a pointer to a typedef"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + // create a TypeDef on p + td = new TypedefDataType(new CategoryPath("/Category1"), "TD_on_Pointer", p); + union.add(td, "typedef field name", "a typedef on a pointer to a typedef"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -985,52 +913,44 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - // create a TypeDef on p - td = new TypedefDataType(new CategoryPath("/Category1"), "TD_on_Pointer", p); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * - // create an Array of TD_on_Pointer - array = new ArrayDataType(td, 7, td.getLength()); - dtc = union.add(array); - dtc.setFieldName("array of typedef field name"); - dtc.setComment("an array of typedefs on a pointer to a typedef"); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + // create a TypeDef on p + td = new TypedefDataType(new CategoryPath("/Category1"), "TD_on_Pointer", p); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + // create an Array of TD_on_Pointer + array = new ArrayDataType(td, 7, td.getLength()); + union.add(array, "array of typedef field name", + "an array of typedefs on a pointer to a typedef"); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); @@ -1496,59 +1416,52 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest { Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - try { - DataTypeComponent dtc = union.add(new FloatDataType()); - dtc.setComment("my comments"); - dtc.setFieldName("Float Field"); - // edit FavoriteColors - Enum enumm = - (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); - enumm.add("Cyan", 5); - enumm.add("Gold", 8); + union.add(new FloatDataType(), "Float Field", "my comments"); - // create TypeDef on pointer to an Array of pointers + // edit FavoriteColors + Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); + enumm.add("Cyan", 5); + enumm.add("Gold", 8); - Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * - p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * + // create TypeDef on pointer to an Array of pointers - // create an array of FavoriteColors * * * * * - Array array = new ArrayDataType(p, 5, p.getLength()); - p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * + Pointer p = PointerDataType.getPointer(enumm, 4);// FavoriteColors * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * + p = PointerDataType.getPointer(p, 4);// FavoriteColors * * * * * - TypeDef td = - new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); - p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * + // create an array of FavoriteColors * * * * * + Array array = new ArrayDataType(p, 5, p.getLength()); + p = PointerDataType.getPointer(array, 4);// FavoriteColors * * * * *[5] * - // create a TypeDef on p - td = new TypedefDataType(new CategoryPath("/Category1"), "TD_on_Pointer", p); + TypeDef td = + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer", p); + p = PointerDataType.getPointer(td, 4);//TD_MyEnumPointer * - // create an Array of TD_on_Pointer - array = new ArrayDataType(td, 11, td.getLength()); - array = new ArrayDataType(array, 10, array.getLength()); - array = new ArrayDataType(array, 9, array.getLength()); - array = new ArrayDataType(array, 8, array.getLength()); - array = new ArrayDataType(array, 7, array.getLength()); - array = new ArrayDataType(array, 6, array.getLength()); - array = new ArrayDataType(array, 5, array.getLength()); + // create a TypeDef on p + td = new TypedefDataType(new CategoryPath("/Category1"), "TD_on_Pointer", p); - // create a pointer to array - p = PointerDataType.getPointer(array, 4);//TD_on_Pointer[5][6][7][8][9][10][11] * - dtc = union.add(p); - Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - s.add(new WordDataType()); + // create an Array of TD_on_Pointer + array = new ArrayDataType(td, 11, td.getLength()); + array = new ArrayDataType(array, 10, array.getLength()); + array = new ArrayDataType(array, 9, array.getLength()); + array = new ArrayDataType(array, 8, array.getLength()); + array = new ArrayDataType(array, 7, array.getLength()); + array = new ArrayDataType(array, 6, array.getLength()); + array = new ArrayDataType(array, 5, array.getLength()); - union = - new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); - union.add(s); - union.add(new ByteDataType()); - dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); - } - catch (DuplicateNameException e) { - Assert.fail("Got Duplicate name exception!"); - } + // create a pointer to array + p = PointerDataType.getPointer(array, 4);//TD_on_Pointer[5][6][7][8][9][10][11] * + union.add(p); + + Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); + s.add(new WordDataType()); + + union = new UnionDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); + union.add(s); + union.add(new ByteDataType()); + dtm.addDataType(union, DataTypeConflictHandler.DEFAULT_HANDLER); } }); executeMerge(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorCellEditTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorCellEditTest.java index 4a162b8d25..efca0fc865 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorCellEditTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorCellEditTest.java @@ -550,11 +550,6 @@ public class StackEditorCellEditTest extends AbstractStackEditorTest { triggerActionInCellEditor(KeyEvent.VK_UP); waitForSwing(); rowNum--; -// DataTypeComponent dtc = model.getComponent(rowNum); -// if (dtc.getOffset() < ((StackEditorModel) model).getParameterOffset()) { -// assertNotEditingField(); -// break; -// } assertIsEditingField(rowNum, colNum); } while (rowNum > 0) { diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java index 1840d1cbbd..1e449b9578 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -47,7 +47,9 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest { DataType dataTypeCopy = composite.copy(null); Composite compositeCopy = (Composite) dataTypeCopy; int fieldIndex = 0; - setName(compositeCopy, fieldIndex); + + DataTypeComponent component = compositeCopy.getComponent(fieldIndex); + component.setFieldName("newName"); HTMLDataTypeRepresentation representation = ToolTipUtils.getHTMLRepresentation(composite); HTMLDataTypeRepresentation otherRepresentation = @@ -789,8 +791,8 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest { assertEquals("ccc ddd", l3a.get(1)); //[a bbbbbbbb, bbbbbbbbbb, bbbbbbbbbb, bbbbbb c] - List l4 = HTMLDataTypeRepresentation.breakLongLineAtWordBoundaries( - "a bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb c", 10); + List l4 = HTMLDataTypeRepresentation + .breakLongLineAtWordBoundaries("a bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb c", 10); assertEquals(4, l4.size()); assertEquals("a bbbbbbbb", l4.get(0)); assertEquals("bbbbbbbbbb", l4.get(1)); @@ -1219,18 +1221,6 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest { } } - private void setName(Composite c, int fieldIndex) { - DataTypeComponent component = c.getComponent(fieldIndex); - try { - component.setFieldName("newName"); - } - catch (DuplicateNameException e) { - // shouldn't happen - e.printStackTrace(); - Assert.fail("Unexpected duplicate name"); - } - } - private void assertCompositeHeaderEquals(HTMLDataTypeRepresentation[] diffedRepresentations) { List headerLines = ((CompositeDataTypeHTMLRepresentation) diffedRepresentations[0]).headerContent; diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java index ba70b5efb6..03c480fed6 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/StructureDataTypeTest.java @@ -116,6 +116,22 @@ public class StructureDataTypeTest extends AbstractGenericTest { assertEquals("Comment4", dtc.getComment()); assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + dtc = struct.add(ByteDataType.dataType, "field3", "new comment"); + assertEquals(8, dtc.getOffset()); + assertEquals(4, dtc.getOrdinal()); + assertEquals("field3", dtc.getFieldName()); // non-duplicate name was imposed + assertEquals("new comment", dtc.getComment()); + assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + assertNotNull(struct.findComponent("field3")); // which one is returned is arbitrary + + dtc = struct.add(ByteDataType.dataType, "field3 1", "new comment"); + assertEquals(9, dtc.getOffset()); + assertEquals(5, dtc.getOrdinal()); + assertEquals("field3_1", dtc.getFieldName()); // non-duplicate name was imposed + assertEquals("new comment", dtc.getComment()); + assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + assertEquals(dtc, struct.findComponent("field3_1")); + } @Test @@ -1306,6 +1322,22 @@ public class StructureDataTypeTest extends AbstractGenericTest { assertEquals(8, comps[3].getOffset()); } + @Test + public void testDelete() { + + assertNotNull(struct.findComponent("field1")); + + struct.delete(0); + + assertNull(struct.findComponent("field1")); + + assertEquals(7, struct.getLength()); + assertEquals(3, struct.getNumComponents()); + DataTypeComponent[] comps = struct.getDefinedComponents(); + assertEquals(DWordDataType.class, comps[1].getDataType().getClass()); + assertEquals(2, comps[1].getOffset()); + } + @Test public void testDeleteManyBF() throws InvalidDataTypeException { @@ -1356,16 +1388,6 @@ public class StructureDataTypeTest extends AbstractGenericTest { assertEquals(5, comps[1].getOffset()); } - @Test - public void testDelete() { - struct.delete(1); - assertEquals(6, struct.getLength()); - assertEquals(3, struct.getNumComponents()); - DataTypeComponent[] comps = struct.getDefinedComponents(); - assertEquals(DWordDataType.class, comps[1].getDataType().getClass()); - assertEquals(1, comps[1].getOffset()); - } - @Test public void testDeleteBF() throws InvalidDataTypeException { @@ -1409,8 +1431,12 @@ public class StructureDataTypeTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf2")); + struct.delete(3); + assertNull(struct.findComponent("bf2")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" + "pack(disabled)\n" + @@ -1426,8 +1452,12 @@ public class StructureDataTypeTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf3")); + struct.delete(3); + assertNull(struct.findComponent("bf3")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" + "pack(disabled)\n" + @@ -1443,8 +1473,12 @@ public class StructureDataTypeTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf4")); + struct.delete(4); + assertNull(struct.findComponent("bf4")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" + "pack(disabled)\n" + @@ -1461,8 +1495,12 @@ public class StructureDataTypeTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf1")); + struct.delete(2); + assertNull(struct.findComponent("bf1")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" + "pack(disabled)\n" + @@ -1731,6 +1769,21 @@ public class StructureDataTypeTest extends AbstractGenericTest { } + @Test + public void testGetComponentByName() { + DataTypeComponent dtc = struct.findComponent("field1"); + assertNotNull(dtc); + assertEquals("field1", dtc.getFieldName()); + + dtc = struct.findComponent("field3"); + assertNotNull(dtc); + assertEquals("field3", dtc.getFieldName()); + + dtc = struct.findComponent("field4"); + assertNotNull(dtc); + assertEquals("field4", dtc.getFieldName()); + } + @Test public void testGetComponentAt() { /** @@ -2629,6 +2682,66 @@ public class StructureDataTypeTest extends AbstractGenericTest { } } + @Test + public void testFieldNameWhitespaceConvertedToUnderscores() { + StructureDataType newStruct = new StructureDataType("Test", 0); + DataTypeComponent component = newStruct.add(new ByteDataType(), " name with spaces", null); + assertEquals("name_with_spaces", component.getFieldName()); + + component = newStruct.getComponent(0); + component.setFieldName(" name in db with spaces "); + assertEquals("name_in_db_with_spaces", component.getFieldName()); + + component = newStruct.add(new ByteDataType(), " another test ", null); + assertEquals("another_test", component.getFieldName()); + + newStruct.insert(0, new ByteDataType(), 1, " insert test ", ""); + component = newStruct.getComponent(0); + assertEquals("insert_test", component.getFieldName()); + + newStruct.replace(0, new ByteDataType(), 1, " insert test ", ""); + component = newStruct.getComponent(0); + assertEquals("insert_test", component.getFieldName()); + } + + @Test + public void testDefaultFieldNames() { + StructureDataType newStruct = new StructureDataType("Test", 0); + DataTypeComponent component = newStruct.add(new ByteDataType(), " ", null); + assertNull(component.getFieldName()); + + component = newStruct.add(new ByteDataType(), null, null); + assertNull(component.getFieldName()); + + component = newStruct.getComponent(0); + assertNull(component.getFieldName()); + + component.setFieldName(" "); + assertNull(component.getFieldName()); + + component = newStruct.add(new ByteDataType(), null, null); + assertNull(component.getFieldName()); + + component = newStruct.add(new ByteDataType(), " ", null); + assertNull(component.getFieldName()); + + newStruct.insert(0, new ByteDataType(), 1, null, ""); + component = newStruct.getComponent(0); + assertNull(component.getFieldName()); + + newStruct.insert(0, new ByteDataType(), 1, " ", ""); + component = newStruct.getComponent(0); + assertNull(component.getFieldName()); + + newStruct.replace(0, new ByteDataType(), 1, null, ""); + component = newStruct.getComponent(0); + assertNull(component.getFieldName()); + + newStruct.replace(0, new ByteDataType(), 1, " ", ""); + component = newStruct.getComponent(0); + assertNull(component.getFieldName()); + } + protected DataTypeManager createBigEndianDataTypeManager() { DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null); dataOrg.setBigEndian(true); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java index 306e97e44c..53bc7ff554 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/model/data/UnionDataTypeTest.java @@ -592,6 +592,61 @@ public class UnionDataTypeTest extends AbstractGenericTest { } } + @Test + public void testFieldNameWhitespaceConvertedToUnderscores() { + UnionDataType newUnion = new UnionDataType("Test"); + DataTypeComponent component = newUnion.add(new ByteDataType(), " name with spaces", null); + assertEquals("name_with_spaces", component.getFieldName()); + + component = newUnion.getComponent(0); + component.setFieldName(" name in db with spaces "); + assertEquals("name_in_db_with_spaces", component.getFieldName()); + + component = newUnion.add(new ByteDataType(), " another test ", null); + assertEquals("another_test", component.getFieldName()); + + newUnion.insert(0, new ByteDataType(), 1, " insert test ", ""); + component = newUnion.getComponent(0); + assertEquals("insert_test", component.getFieldName()); + + newUnion.insert(1, new ByteDataType(), 1, " insert test ", ""); + component = newUnion.getComponent(1); + assertEquals("insert_test", component.getFieldName()); + } + + @Test + public void testDefaultFieldNames() { + UnionDataType newUnion = new UnionDataType("Test"); + DataTypeComponent component = newUnion.add(new ByteDataType(), " ", null); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + + component = newUnion.add(new ByteDataType(), null, null); + assertNull(component.getFieldName()); + assertEquals("field1", component.getDefaultFieldName()); + + component = newUnion.getComponent(0); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + + component.setFieldName(" "); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + + component = newUnion.add(new ByteDataType(), null, null); + assertNull(component.getFieldName()); + assertEquals("field2", component.getDefaultFieldName()); + + component = newUnion.add(new ByteDataType(), " ", null); + assertNull(component.getFieldName()); + assertEquals("field3", component.getDefaultFieldName()); + + newUnion.insert(0, new ByteDataType(), 1, null, ""); + component = newUnion.getComponent(0); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + } + protected DataTypeManager createBigEndianDataTypeManager() { DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null); dataOrg.setBigEndian(true); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java index 6307836a97..4d30fe8cd6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java @@ -1225,13 +1225,7 @@ public class DefaultCompositeMember extends CompositeMember { for (int i = 0; i < count; i++) { DataTypeComponent component = composite.getComponent(i); if (oldFieldName.equals(component.getFieldName())) { - try { - component.setFieldName(newFieldName); - } - catch (DuplicateNameException e) { - Msg.error(this, "Failed to rename temporary component name: " + - getDataTypeName() + "." + oldFieldName + " -> " + newFieldName); - } + component.setFieldName(newFieldName); break; } } @@ -1356,9 +1350,8 @@ public class DefaultCompositeMember extends CompositeMember { * @throws CancelledException if monitor is cancelled */ public static boolean applyDataTypeMembers(Composite composite, boolean packingDisabled, - boolean isClass, int preferredCompositeSize, - List members, Consumer errorConsumer, TaskMonitor monitor) - throws CancelledException { + boolean isClass, int preferredCompositeSize, List members, + Consumer errorConsumer, TaskMonitor monitor) throws CancelledException { Composite editComposite = composite; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java index 20d38a68be..13c62ec958 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapter.java @@ -19,7 +19,7 @@ import java.io.IOException; import db.*; import ghidra.framework.data.OpenMode; -import ghidra.util.StringUtilities; +import ghidra.program.model.data.InternalDataTypeComponent; import ghidra.util.exception.VersionException; /** @@ -61,19 +61,20 @@ abstract class ComponentDBAdapter { * @param length the total length of this component. * @param ordinal the component's ordinal. * @param offset the component's offset. - * @param name the component's name. This name will be subject to revision based upon - * {@link #cleanUpFieldName(String)} method use. + * @param fieldName the component's name (may be null). This method may sanitize the name + * (see {@link InternalDataTypeComponent#cleanupFieldName(String)}) before storing. + * {@link InternalDataTypeComponent#cleanupFieldName(String)} method use. * @param comment a comment about this component * @return the component data type record. * @throws IOException if there is a problem accessing the database. */ abstract DBRecord createRecord(long dataTypeID, long parentID, int length, int ordinal, - int offset, String name, String comment) throws IOException; + int offset, String fieldName, String comment) throws IOException; /** * Gets the record for the indicated component data type. * @param componentID the ID of the component data type to retrieve. - * @return the component record + * @return the component record or null if not found * @throws IOException if there is a problem accessing the database. */ abstract DBRecord getRecord(long componentID) throws IOException; @@ -89,8 +90,8 @@ abstract class ComponentDBAdapter { /** * Updates the component data type table with the provided record. *

- * IMPORTANT: Any modification of field name should be subject to {@link #cleanUpFieldName(String)} - * use first. + * IMPORTANT: Any modification of field name should be subject to + * {@link InternalDataTypeComponent#cleanupFieldName(String)} use first. * * @param record the new record * @throws IOException if there is a problem accessing the database. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java index 8fc34311c6..af8b57a38e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ComponentDBAdapterV0.java @@ -17,6 +17,8 @@ package ghidra.program.database.data; import java.io.IOException; +import org.apache.commons.lang3.StringUtils; + import db.*; import ghidra.program.model.data.InternalDataTypeComponent; import ghidra.util.exception.VersionException; @@ -73,15 +75,19 @@ class ComponentDBAdapterV0 extends ComponentDBAdapter { @Override DBRecord createRecord(long dataTypeID, long parentID, int length, int ordinal, int offset, - String name, String comment) throws IOException { + String fieldName, String comment) throws IOException { long key = DataTypeManagerDB.createKey(DataTypeManagerDB.COMPONENT, componentTable.getKey()); + if (StringUtils.isBlank(comment)) { + comment = null; + } + fieldName = InternalDataTypeComponent.cleanupFieldName(fieldName); + DBRecord record = ComponentDBAdapter.COMPONENT_SCHEMA.createRecord(key); record.setLongValue(ComponentDBAdapter.COMPONENT_PARENT_ID_COL, parentID); record.setLongValue(ComponentDBAdapter.COMPONENT_OFFSET_COL, offset); record.setLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL, dataTypeID); - record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, - InternalDataTypeComponent.cleanupFieldName(name)); + record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, fieldName); record.setString(ComponentDBAdapter.COMPONENT_COMMENT_COL, comment); record.setIntValue(ComponentDBAdapter.COMPONENT_SIZE_COL, length); record.setIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL, ordinal); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java index 12b5e41c4e..f1fcfa5111 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CompositeDB.java @@ -18,6 +18,7 @@ package ghidra.program.database.data; import java.io.IOException; import java.util.ConcurrentModificationException; import java.util.Objects; +import java.util.function.Consumer; import db.DBRecord; import ghidra.docking.settings.Settings; @@ -62,6 +63,111 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal { */ protected abstract void initialize(); + protected DataTypeComponentDB createComponent(long dtID, int length, int ordinal, int offset, + String componentName, String comment) { + + DBRecord rec; + try { + rec = componentAdapter.createRecord(dtID, key, length, ordinal, offset, componentName, + comment); + return new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); + } + catch (IOException e) { + dataMgr.dbError(e); // throws RuntimeException + } + // Will never reach here + throw new AssertionError(); + } + + @Override + public abstract DataTypeComponentDB getComponent(int ordinal) throws IndexOutOfBoundsException; + + private DataTypeComponentDB getValidatedComponent(DataTypeComponentDB component) + throws IOException { + // Verify that component is still valid for this composite + DBRecord rec = componentAdapter.getRecord(component.getKey()); + if (rec == null || rec.getLongValue(ComponentDBAdapter.COMPONENT_PARENT_ID_COL) != key) { + throw new ConcurrentModificationException("Component has been deleted."); + } + + // Verify specified component instance is + DataTypeComponentDB myDtc = getComponent(component.getOrdinal()); + if (myDtc != component) { + // supplied instance is stale - it should exist in our defined component list + myDtc = getComponent(rec.getIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL)); + } + return myDtc; + } + + /** + * Set the name on a possibly stale component in support of the + * {@link DataTypeComponent#setFieldName(String)} method. + *

+ * If the field name is empty it will be set to null, + * which is the default field name. The field name may be sanitized to convert all whitespace + * characters to an underscore. If a name conflict occurs with another component, a one-up + * number suffix will be added to avoid duplication. + * + * @param component data type component which has this composite as its parent. + * @param name new field name or null + * @return updated component instance + */ + protected DataTypeComponentDB setFieldName(DataTypeComponentDB component, String name) { + lock.acquire(); + try { + checkDeleted(); + if (component.getRecord() == null) { + return component; // unable to change undefined component + } + + // Verify specified component instance is + DataTypeComponentDB myDtc = getValidatedComponent(component); + if (myDtc.doSetFieldName(name)) { + dataMgr.dataTypeChanged(this, false); + } + return myDtc; // return modified component instance + } + catch (IOException e) { + dataMgr.dbError(e); + } + finally { + lock.release(); + } + return component; // unchanged + } + + /** + * Set the comment on a possibly stale component in support of the + * {@link DataTypeComponent#setComment(String)} method. + * + * @param component data type component which has this composite as its parent. + * @param comment comment string + * @return updated component instance + */ + protected DataTypeComponentDB setComment(DataTypeComponentDB component, String comment) { + lock.acquire(); + try { + checkDeleted(); + if (component.getRecord() == null) { + return component; // unable to change undefined component + } + + // Verify specified component instance is + DataTypeComponentDB myDtc = getValidatedComponent(component); + if (myDtc.doSetComment(comment)) { + dataMgr.dataTypeChanged(this, false); + } + return myDtc; // return modified component instance + } + catch (IOException e) { + dataMgr.dbError(e); + } + finally { + lock.release(); + } + return component; // unchanged + } + @Override public final int getAlignedLength() { return getLength(); @@ -329,9 +435,20 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal { compositeAdapter.updateRecord(record, true); } - protected void removeComponentRecord(long compKey) throws IOException { - componentAdapter.removeRecord(compKey); - dataMgr.getSettingsAdapter().removeAllSettingsRecords(compKey); + /** + * Removes a defined component without any alteration to other components or the components + * list, removes parent association for component datatype and remove name-map entry. + * @param dtc datatype component + * @throws IOException if an IO error occurs + */ + protected void doDelete(DataTypeComponentDB dtc) throws IOException { + + dtc.getDataType().removeParent(this); + + // Remove component record + long dtcKey = dtc.getKey(); + componentAdapter.removeRecord(dtcKey); + dataMgr.getSettingsAdapter().removeAllSettingsRecords(dtcKey); } /** @@ -673,6 +790,8 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal { @Override public abstract DataTypeComponentDB[] getDefinedComponents(); + abstract void forEachDefinedComponent(Consumer dtcConsumer); + @Override protected void postPointerResolve(DataType definitionDt, DataTypeConflictHandler handler) { Composite composite = (Composite) definitionDt; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java index 89d3598083..36e08d53d0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java @@ -16,14 +16,13 @@ package ghidra.program.database.data; import java.io.IOException; +import java.util.Objects; import org.apache.commons.lang3.StringUtils; import db.DBRecord; import ghidra.docking.settings.*; import ghidra.program.model.data.*; -import ghidra.util.SystemUtilities; -import ghidra.util.exception.DuplicateNameException; /** * Database implementation for a DataTypeComponent. If this @@ -215,14 +214,26 @@ class DataTypeComponentDB implements InternalDataTypeComponent { } @Override - public void setComment(String comment) { + public DataTypeComponentDB setComment(String comment) { + if (record != null) { + return parent.setComment(this, comment); + } + return this; + } + + boolean doSetComment(String comment) { if (record != null) { if (StringUtils.isBlank(comment)) { comment = null; } - record.setString(ComponentDBAdapter.COMPONENT_COMMENT_COL, comment); - updateRecord(true); + if (!Objects.equals(comment, + record.getString(ComponentDBAdapter.COMPONENT_COMMENT_COL))) { + record.setString(ComponentDBAdapter.COMPONENT_COMMENT_COL, comment); + updateRecord(true); // updates DB and timestamp without notification + return true; + } } + return false; } @Override @@ -236,12 +247,27 @@ class DataTypeComponentDB implements InternalDataTypeComponent { } @Override - public void setFieldName(String name) throws DuplicateNameException { + public DataTypeComponentDB setFieldName(String name) { if (record != null) { - String fieldName = InternalDataTypeComponent.cleanupFieldName(name); - record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, fieldName); - updateRecord(true); + // Parent must first validate instance before setting field name + return parent.setFieldName(this, name); } + return this; + } + + boolean doSetFieldName(String name) { + if (record != null) { + String oldName = record.getString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL); + + // Cleanup invalid names and make unique within this composite + String fieldName = InternalDataTypeComponent.cleanupFieldName(name); + if (!Objects.equals(oldName, fieldName)) { + record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, fieldName); + updateRecord(true); // updates DB and timestamp without notification + return true; + } + } + return false; } @Override @@ -261,8 +287,8 @@ class DataTypeComponentDB implements InternalDataTypeComponent { if (offset != dtc.getOffset() || getLength() != dtc.getLength() || ordinal != dtc.getOrdinal() || - !SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) || - !SystemUtilities.isEqual(getComment(), dtc.getComment())) { + !Objects.equals(getFieldName(), dtc.getFieldName()) || + !Objects.equals(getComment(), dtc.getComment())) { return false; } if (!(myDt instanceof Pointer) && !myDt.getPathName().equals(otherDt.getPathName())) { @@ -307,8 +333,8 @@ class DataTypeComponentDB implements InternalDataTypeComponent { (myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false; // Components don't need to have matching offset when structure has packing enabled if ((!isPacked && (offset != dtc.getOffset())) || - !SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) || - !SystemUtilities.isEqual(getComment(), dtc.getComment())) { + !Objects.equals(getFieldName(), dtc.getFieldName()) || + !Objects.equals(getComment(), dtc.getComment())) { return false; } @@ -407,27 +433,36 @@ class DataTypeComponentDB implements InternalDataTypeComponent { } /** - * Perform special-case component update that does not result in size or alignment changes. - * @param name new component name + * Perform special-case component update that does not result in size or alignment changes + * and does not modify last change time. + * @param fieldName new component name or null. If not null a unique component name will be forced. * @param dt new resolved datatype * @param comment new comment */ - void update(String name, DataType dt, String comment) { + void update(String fieldName, DataType dt, String comment) { if (record != null) { + + String oldName = record.getString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL); + + fieldName = InternalDataTypeComponent.cleanupFieldName(fieldName); + if (!Objects.equals(oldName, fieldName)) { + record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, fieldName); + } + if (StringUtils.isBlank(comment)) { comment = null; } - String fieldName = InternalDataTypeComponent.cleanupFieldName(name); - record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, fieldName); + record.setLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL, dataMgr.getResolvedID(dt)); - record.setString(ComponentDBAdapter.COMPONENT_COMMENT_COL, comment); + record.setString(ComponentDBAdapter.COMPONENT_COMMENT_COL, + StringUtils.isBlank(comment) ? null : comment); updateRecord(false); } } @Override public void setDataType(DataType newDt) { - // intended for internal use only - note exsiting settings should be preserved + // Internal Interface use only - existing settings should be preserved if (record != null) { record.setLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL, dataMgr.getResolvedID(newDt)); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java index 58dfc2794e..0c55620640 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java @@ -2646,6 +2646,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { status = compositeAdapter.removeRecord(dataTypeID); break; case COMPONENT: + // NOTE: This is only used when completely removing a composite datatype status = componentAdapter.removeRecord(dataTypeID); break; case TYPEDEF: diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java index 71626c5149..42a494d870 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java @@ -15,7 +15,7 @@ */ package ghidra.program.database.data; -import com.google.common.base.Predicate; +import java.util.function.Predicate; import ghidra.docking.settings.*; import ghidra.program.model.data.*; @@ -88,7 +88,7 @@ class DataTypeSettingsDB implements Settings { return false; } if (allowedSettingPredicate != null && - !allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) { + !allowedSettingPredicate.test(settingsDefinition.getStorageKey())) { return false; } return true; @@ -118,7 +118,7 @@ class DataTypeSettingsDB implements Settings { return false; } if (name != null && allowedSettingPredicate != null && - !allowedSettingPredicate.apply(name)) { + !allowedSettingPredicate.test(name)) { Msg.warn(this, "Ignored disallowed setting '" + name + "'"); return false; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java index 5970c7e42f..0643501575 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java @@ -17,6 +17,7 @@ package ghidra.program.database.data; import java.io.IOException; import java.util.*; +import java.util.function.Consumer; import db.DBRecord; import db.Field; @@ -182,8 +183,8 @@ class StructureDB extends CompositeDB implements StructureInternal { } } - private DataTypeComponent doAdd(DataType dataType, int length, String name, String comment, - boolean validatePackAndNotify) + private DataTypeComponent doAdd(DataType dataType, int length, String name, + String comment, boolean validatePackAndNotify) throws DataTypeDependencyException, IllegalArgumentException { lock.acquire(); @@ -204,9 +205,10 @@ class StructureDB extends CompositeDB implements StructureInternal { } else { int componentLength = getPreferredComponentLength(dataType, length); - DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), - key, componentLength, numComponents, structLength, name, comment); - dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); + + dtc = createComponent(dataMgr.getResolvedID(dataType), componentLength, + numComponents, structLength, name, comment); + dataType.addParent(this); components.add(dtc); } @@ -261,6 +263,7 @@ class StructureDB extends CompositeDB implements StructureInternal { } else { index = backupToFirstComponentContainingOffset(index, len); + index = afterNonZeroComponentsAtOffset(index, len); } int definedComponentCount = components.size(); if (index >= 0 && index < definedComponentCount) { @@ -370,9 +373,10 @@ class StructureDB extends CompositeDB implements StructureInternal { length = getPreferredComponentLength(dataType, length); int offset = getComponent(ordinal).getOffset(); - DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, - length, ordinal, offset, name, comment); - DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); + + DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(dataType), length, + ordinal, offset, name, comment); + dataType.addParent(this); shiftOffsets(idx, 1, dtc.getLength()); components.add(idx, dtc); @@ -383,13 +387,9 @@ class StructureDB extends CompositeDB implements StructureInternal { catch (DataTypeDependencyException e) { throw new IllegalArgumentException(e.getMessage(), e); } - catch (IOException e) { - dataMgr.dbError(e); - } finally { lock.release(); } - return null; } @Override @@ -544,9 +544,9 @@ class StructureDB extends CompositeDB implements StructureInternal { BitFieldDataType bitfieldDt = new BitFieldDBDataType(baseDataType, bitSize, storageBitOffset); - DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(bitfieldDt), key, + DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(bitfieldDt), bitfieldDt.getStorageSize(), ordinal, revisedOffset, componentName, comment); - DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); + bitfieldDt.addParent(this); // has no affect components.add(startIndex, dtc); @@ -554,13 +554,9 @@ class StructureDB extends CompositeDB implements StructureInternal { notifySizeChanged(false); return dtc; } - catch (IOException e) { - dataMgr.dbError(e); - } finally { lock.release(); } - return null; } @Override @@ -597,7 +593,8 @@ class StructureDB extends CompositeDB implements StructureInternal { /** * Removes a defined component at the specified index from the components list without any - * alteration to other components and removes parent association for component datatype. + * alteration to other components, removes parent association for component datatype and + * remove name-map entry. * @param index defined component index * @return the defined component which was removed. * @throws IOException if an IO error occurs @@ -608,17 +605,6 @@ class StructureDB extends CompositeDB implements StructureInternal { return dtc; } - /** - * Removes a defined component without any alteration to other components or the components - * list and removes parent association for component datatype. - * @param dtc datatype component - * @throws IOException if an IO error occurs - */ - private void doDelete(DataTypeComponentDB dtc) throws IOException { - dtc.getDataType().removeParent(this); - removeComponentRecord(dtc.getKey()); - } - /** * Removes a defined component at the specified index. *

@@ -1301,6 +1287,11 @@ class StructureDB extends CompositeDB implements StructureInternal { } } + @Override + void forEachDefinedComponent(Consumer dtcConsumer) { + components.forEach(dtcConsumer); + } + @Override public final DataTypeComponent insertAtOffset(int offset, DataType dataType, int length) throws IllegalArgumentException { @@ -1384,10 +1375,11 @@ class StructureDB extends CompositeDB implements StructureInternal { return new DataTypeComponentDB(dataMgr, this, ordinal, offset); } - DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, - length, ordinal, offset, name, comment); + length = getPreferredComponentLength(dataType, length); + + DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(dataType), length, + ordinal, offset, name, comment); dataType.addParent(this); - DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); shiftOffsets(index, 1 + additionalShift, length + additionalShift); components.add(index, dtc); repack(false, false); @@ -1397,13 +1389,9 @@ class StructureDB extends CompositeDB implements StructureInternal { catch (DataTypeDependencyException e) { throw new IllegalArgumentException(e.getMessage(), e); } - catch (IOException e) { - dataMgr.dbError(e); - } finally { lock.release(); } - return null; } /** @@ -1442,6 +1430,7 @@ class StructureDB extends CompositeDB implements StructureInternal { return oldComponent; } + // Note: a unique componentName will be imposed if not null DataTypeComponent replaceComponent = replaceComponents(replacedComponents, dataType, offset, length, componentName, comment); @@ -1729,13 +1718,11 @@ class StructureDB extends CompositeDB implements StructureInternal { for (int i = 0; i < otherComponents.length; i++) { resolvedDts[i] = doCheckedResolve(otherComponents[i].getDataType()); } - for (DataTypeComponentDB dtc : components) { - dtc.getDataType().removeParent(this); - long compKey = dtc.getKey(); - componentAdapter.removeRecord(compKey); - dataMgr.getSettingsAdapter().removeAllSettingsRecords(compKey); - } + // Remove all existing components + for (DataTypeComponentDB dtc : components) { + doDelete(dtc); + } components.clear(); numComponents = 0; structLength = 0; @@ -1799,8 +1786,7 @@ class StructureDB extends CompositeDB implements StructureInternal { } } - private void doReplaceWithNonPacked(Structure struct, DataType[] resolvedDts) - throws IOException { + private void doReplaceWithNonPacked(Structure struct, DataType[] resolvedDts) { // caller responsible for record updates @@ -1836,17 +1822,16 @@ class StructureDB extends CompositeDB implements StructureInternal { length = getPreferredComponentLength(dt, -1, maxLength); } - DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(dt), key, length, + DataTypeComponentDB newDtc = createComponent(dataMgr.getResolvedID(dt), length, dtc.getOrdinal(), dtc.getOffset(), dtc.getFieldName(), dtc.getComment()); + dt.addParent(this); - DataTypeComponentDB newDtc = - new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); components.add(newDtc); } } private void doCopy(Structure struct, DataTypeComponent[] definedComponents, - DataType[] resolvedDts) throws IOException { + DataType[] resolvedDts) { // simple replication of struct - caller must perform record updates structLength = struct.isZeroLength() ? 0 : struct.getLength(); @@ -1857,12 +1842,11 @@ class StructureDB extends CompositeDB implements StructureInternal { for (int i = 0; i < otherComponents.length; i++) { DataTypeComponent dtc = otherComponents[i]; DataType dt = resolvedDts[i]; // ancestry check already performed by caller - DBRecord rec = - componentAdapter.createRecord(dataMgr.getResolvedID(dt), key, dtc.getLength(), - dtc.getOrdinal(), dtc.getOffset(), dtc.getFieldName(), dtc.getComment()); + + DataTypeComponentDB newDtc = createComponent(dataMgr.getResolvedID(dt), dtc.getLength(), + dtc.getOrdinal(), dtc.getOffset(), dtc.getFieldName(), dtc.getComment()); + dt.addParent(this); - DataTypeComponentDB newDtc = - new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); components.add(newDtc); } } @@ -2345,10 +2329,10 @@ class StructureDB extends CompositeDB implements StructureInternal { DataTypeComponentDB newDtc = null; if (!clearOnly) { // insert new component - DBRecord rec = componentAdapter.createRecord(dataMgr.getResolvedID(resolvedDataType), - key, length, newOrdinal, newOffset, name, comment); + newDtc = createComponent(dataMgr.getResolvedID(resolvedDataType), length, newOrdinal, + newOffset, name, comment); + resolvedDataType.addParent(this); - newDtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); components.add(index, newDtc); } @@ -2477,15 +2461,7 @@ class StructureDB extends CompositeDB implements StructureInternal { try { checkDeleted(); for (DataTypeComponentDB dtc : components) { - dtc.getDataType().removeParent(this); - try { - long compKey = dtc.getKey(); - componentAdapter.removeRecord(compKey); - dataMgr.getSettingsAdapter().removeAllSettingsRecords(compKey); - } - catch (IOException e) { - dataMgr.dbError(e); - } + doDelete(dtc); } components.clear(); structLength = 0; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java index 013c4baa35..2823b06dbc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java @@ -17,6 +17,7 @@ package ghidra.program.database.data; import java.io.IOException; import java.util.*; +import java.util.function.Consumer; import db.DBRecord; import db.Field; @@ -61,7 +62,9 @@ class UnionDB extends CompositeDB implements UnionInternal { Field[] ids = componentAdapter.getComponentIdsInComposite(key); for (Field id : ids) { DBRecord rec = componentAdapter.getRecord(id.getLongValue()); - components.add(new DataTypeComponentDB(dataMgr, componentAdapter, this, rec)); + DataTypeComponentDB component = + new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); + components.add(component); } } catch (IOException e) { @@ -122,8 +125,8 @@ class UnionDB extends CompositeDB implements UnionInternal { return length; } - private DataTypeComponent doAdd(DataType dataType, int length, String name, String comment, - boolean validateAlignAndNotify) throws DataTypeDependencyException { + private DataTypeComponent doAdd(DataType dataType, int length, String name, + String comment, boolean validateAlignAndNotify) throws DataTypeDependencyException { dataType = validateDataType(dataType); @@ -145,19 +148,6 @@ class UnionDB extends CompositeDB implements UnionInternal { return dtc; } - private DataTypeComponentDB createComponent(long dtID, int length, int ordinal, int offset, - String name, String comment) { - DBRecord rec; - try { - rec = componentAdapter.createRecord(dtID, key, length, ordinal, offset, name, comment); - return new DataTypeComponentDB(dataMgr, componentAdapter, this, rec); - } - catch (IOException e) { - dataMgr.dbError(e); - } - return null; - } - @Override public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name, String comment) throws IllegalArgumentException { @@ -222,8 +212,8 @@ class UnionDB extends CompositeDB implements UnionInternal { getComputedAlignment(true); // ensure previous alignment has been stored DataTypeComponentDB dtc = components.remove(ordinal); - dtc.getDataType().removeParent(this); - removeComponentRecord(dtc.getKey()); + doDelete(dtc); + shiftOrdinals(ordinal, -1); if (!repack(false, true)) { @@ -265,8 +255,7 @@ class UnionDB extends CompositeDB implements UnionInternal { int ordinal = dtc.getOrdinal(); if (ordinals.contains(ordinal)) { // component removed - delete record - dtc.getDataType().removeParent(this); - removeComponentRecord(dtc.getKey()); + doDelete(dtc); --ordinalAdjustment; } else { @@ -347,9 +336,9 @@ class UnionDB extends CompositeDB implements UnionInternal { } for (DataTypeComponentDB dtc : components) { - dtc.getDataType().removeParent(this); - removeComponentRecord(dtc.getKey()); + doDelete(dtc); } + components.clear(); unionAlignment = -1; computedAlignment = -1; @@ -358,7 +347,8 @@ class UnionDB extends CompositeDB implements UnionInternal { for (int i = 0; i < otherComponents.length; i++) { DataTypeComponent dtc = otherComponents[i]; - doAdd(resolvedDts[i], dtc.getLength(), dtc.getFieldName(), dtc.getComment(), false); + doAdd(resolvedDts[i], dtc.getLength(), dtc.getFieldName(), dtc.getComment(), + false); } repack(false, false); @@ -427,7 +417,7 @@ class UnionDB extends CompositeDB implements UnionInternal { } @Override - public DataTypeComponent getComponent(int ordinal) { + public DataTypeComponentDB getComponent(int ordinal) { lock.acquire(); try { checkIsValid(); @@ -458,6 +448,11 @@ class UnionDB extends CompositeDB implements UnionInternal { return getComponents(); } + @Override + void forEachDefinedComponent(Consumer dtcConsumer) { + components.forEach(dtcConsumer); + } + @Override public DataType copy(DataTypeManager dtm) { UnionDataType union = new UnionDataType(getCategoryPath(), getName(), dtm); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/StructureMerger.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/StructureMerger.java index da6993f46c..4cb2af71a1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/StructureMerger.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/StructureMerger.java @@ -18,7 +18,6 @@ package ghidra.program.database.data.merge; import java.util.List; import ghidra.program.model.data.*; -import ghidra.util.exception.DuplicateNameException; /** * DataType merger for structures. @@ -215,12 +214,7 @@ public class StructureMerger extends DataTypeMerger { otherName)); } if (workingName == null && otherName != null) { - try { - workingComp.setFieldName(otherName); - } - catch (DuplicateNameException e) { - // This exception is going away soon, so ignore it for now - } + workingComp.setFieldName(otherName); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/UnionMerger.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/UnionMerger.java index a2883983d1..0b44903e9d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/UnionMerger.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/merge/UnionMerger.java @@ -16,7 +16,6 @@ package ghidra.program.database.data.merge; import ghidra.program.model.data.*; -import ghidra.util.exception.DuplicateNameException; /** * Datatype merger for Unions @@ -77,13 +76,8 @@ public class UnionMerger extends DataTypeMerger { } private void appySameTypeComponent(DataTypeComponent resultComp, DataTypeComponent component) { - try { - resultComp.setFieldName(component.getFieldName()); - resultComp.setComment(join(resultComp.getComment(), component.getComment())); - } - catch (DuplicateNameException e) { - // can't happen, we already looked for a component with the same name - } + resultComp.setFieldName(component.getFieldName()); + resultComp.setComment(join(resultComp.getComment(), component.getComment())); } private void applySameNamedComponent(DataTypeComponent comp1, DataTypeComponent comp2) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedStructureInspector.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedStructureInspector.java index c648fbd0a6..74d229e9fe 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedStructureInspector.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AlignedStructureInspector.java @@ -117,7 +117,7 @@ public class AlignedStructureInspector extends AlignedStructurePacker { } @Override - public void setComment(String comment) { + public DataTypeComponent setComment(String comment) { throw new UnsupportedOperationException(); } @@ -127,7 +127,7 @@ public class AlignedStructureInspector extends AlignedStructurePacker { } @Override - public void setFieldName(String fieldName) throws DuplicateNameException { + public DataTypeComponent setFieldName(String fieldName) { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Composite.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Composite.java index 2895b51a70..ec104df709 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Composite.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Composite.java @@ -15,7 +15,7 @@ */ package ghidra.program.model.data; -import java.util.Set; +import java.util.*; /** * Interface for common methods in Structure and Union @@ -55,6 +55,61 @@ public interface Composite extends DataType { */ public abstract DataTypeComponent getComponent(int ordinal) throws IndexOutOfBoundsException; + /** + * Find the first component which has the specified case-sensitive field name. + * Note that multiple components may be specified with the same name, if this is a possibility + * the {@link #findComponents(String)} method should be used. Only components with an explicit + * non-default field name will be considered. The name specified may be sanitized to be + * consistent with those permitted by {@link Composite} data types. + * + * @param fieldName field name + * @return first data type component whose field name matches or null if not found + */ + public default DataTypeComponent findComponent(String fieldName) { + + if (getNumDefinedComponents() == 0) { + return null; + } + + fieldName = InternalDataTypeComponent.cleanupFieldName(fieldName); + if (fieldName == null) { + return null; + } + + for (DataTypeComponent dtc : getDefinedComponents()) { + if (fieldName.equals(dtc.getFieldName())) { + return dtc; + } + } + + return null; + } + + /** + * Find all components which have the specified case-sensitive field name. + * Note that multiple components may be specified with the same name, if this is a possibility + * the {@link #findComponents(String)} method should be used. Only components with an explicit + * non-default field name will be considered. The name specified may be sanitized to be + * consistent with those permitted by {@link Composite} data types. + * + * @param name field name + * @return all data type components whose field name matches or empty list if not found + */ + public default List findComponents(String name) { + + if (getNumDefinedComponents() == 0) { + return List.of(); + } + + List list = new ArrayList<>(); + for (DataTypeComponent dtc : getDefinedComponents()) { + if (name.equals(dtc.getFieldName())) { + list.add(dtc); + } + } + return list; + } + /** * Returns an array of Data Type Components that make up this composite including * undefined filler components which may be present within a Structure which has packing disabled. @@ -113,15 +168,16 @@ public interface Composite extends DataType { * automatically to provide the proper alignment. * * @param dataType the datatype to add. - * @param name the field name to associate with this component. - * @param comment the comment to associate with this component. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. + * @param comment the comment to associate with this component. (may be null) * @return the componentDataType created. * @throws IllegalArgumentException if the specified data type is not * allowed to be added to this composite data type. * For example, suppose dt1 contains dt2. Therefore it is not valid * to add dt1 to dt2 since this would cause a cyclic dependency. */ - public DataTypeComponent add(DataType dataType, String name, String comment) + public DataTypeComponent add(DataType dataType, String componentName, String comment) throws IllegalArgumentException; /** @@ -132,8 +188,9 @@ public interface Composite extends DataType { * * @param baseDataType the bitfield base datatype (certain restrictions apply). * @param bitSize the bitfield size in bits - * @param componentName the field name to associate with this component. - * @param comment the comment to associate with this component. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. + * @param comment the comment to associate with this component. (may be null) * @return the componentDataType created whose associated data type will * be BitFieldDataType. * @throws InvalidDataTypeException if the specified data type is @@ -151,16 +208,17 @@ public interface Composite extends DataType { * @param dataType the datatype to add. * @param length the length to associate with the datatype. * For fixed length types a length <= 0 will use the length of the resolved dataType. - * @param name the field name to associate with this component. - * @param comment the comment to associate with this component. + * @param componentName the field name to associate with this component (may be null). + * The name may be sanitized to convert all whitespace characters to an underscore. + * @param comment the comment to associate with this component (may be null). * @return the componentDataType created. * @throws IllegalArgumentException if the specified data type is not * allowed to be added to this composite data type or an invalid length is specified. * For example, suppose dt1 contains dt2. Therefore it is not valid * to add dt1 to dt2 since this would cause a cyclic dependency. */ - public DataTypeComponent add(DataType dataType, int length, String name, String comment) - throws IllegalArgumentException; + public DataTypeComponent add(DataType dataType, int length, String componentName, + String comment) throws IllegalArgumentException; /** * Inserts a new datatype at the specified ordinal position in this composite. @@ -211,8 +269,9 @@ public interface Composite extends DataType { * @param dataType the datatype to insert. * @param length the length to associate with the datatype. * For fixed length types a length <= 0 will use the length of the resolved dataType. - * @param name the field name to associate with this component. - * @param comment the comment to associate with this component. + * @param componentName the field name to associate with this component (may be null). + * The name may be sanitized to convert all whitespace characters to an underscore. + * @param comment the comment to associate with this component. (may be null) * @return the componentDataType created. * @throws IllegalArgumentException if the specified data type is not * allowed to be inserted into this composite data type or an invalid length @@ -221,8 +280,9 @@ public interface Composite extends DataType { * to insert dt1 to dt2 since this would cause a cyclic dependency. * @throws IndexOutOfBoundsException if component ordinal is out of bounds */ - public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name, - String comment) throws IndexOutOfBoundsException, IllegalArgumentException; + public DataTypeComponent insert(int ordinal, DataType dataType, int length, + String componentName, String comment) + throws IndexOutOfBoundsException, IllegalArgumentException; /** * Deletes the component at the given ordinal position. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java index 39810f5f64..e5119b9a65 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java @@ -15,6 +15,8 @@ */ package ghidra.program.model.data; +import java.util.function.Consumer; + import ghidra.docking.settings.Settings; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.model.mem.MemBuffer; @@ -62,6 +64,13 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C description = ""; } + protected DataTypeComponentImpl createComponent(DataType dataType, int length, int ordinal, + int offset, String fieldName, String comment) { + + return new DataTypeComponentImpl(dataType, this, length, ordinal, + offset, fieldName, comment); + } + @Override public final int getAlignedLength() { return getLength(); @@ -441,6 +450,8 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C @Override public abstract int getAlignment(); + abstract void forEachDefinedComponent(Consumer dtcConsumer); + @Override public String toString() { return CompositeInternal.toString(this); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeInternal.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeInternal.java index 6f88bf81c3..420248f8c0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeInternal.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeInternal.java @@ -260,5 +260,4 @@ public interface CompositeInternal extends Composite { buf.append(")"); return buf.toString(); } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponent.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponent.java index 33f83fc764..c3ff106f58 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponent.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponent.java @@ -16,7 +16,6 @@ package ghidra.program.model.data; import ghidra.docking.settings.Settings; -import ghidra.util.exception.DuplicateNameException; /** * DataTypeComponents are holders for the dataTypes that make up composite (Structures @@ -98,9 +97,14 @@ public interface DataTypeComponent { /** * Sets the comment for the component. + *

+ * NOTE: Since a datatype component instance is intended to be immutable a new component + * instance is returned which will reflect the modified component. + * * @param comment this components comment or null to clear comment. + * @return a new component instance which will reflect the change. */ - public void setComment(String comment); + public DataTypeComponent setComment(String comment); /** * Get this component's field name within its parent. @@ -112,17 +116,17 @@ public interface DataTypeComponent { /** * Sets the field name. If the field name is empty it will be set to null, - * which is the default field name. An exception is thrown if one of the - * parent's other components already has the specified field name. + * which is the default field name. The field name may be sanitized to convert all whitespace + * characters to an underscore. If a name conflict occurs with another component, a one-up + * number suffix will be added to avoid duplication. + *

+ * NOTE: Since a datatype component instance is intended to be immutable a new component + * instance is returned which will reflect the modified component. * * @param fieldName the new field name for this component. - * - * @throws DuplicateNameException This is actually never thrown anymore. All the other ways - * of naming fields did not perform this check and it would cause quite a bit of churn to - * add that exception to all the other methods that affect field names. So to be consistent, - * we no longer do the check in this method. + * @return a new component instance which will reflect the change. */ - public void setFieldName(String fieldName) throws DuplicateNameException; + public DataTypeComponent setFieldName(String fieldName); /** * Returns a default field name for this component. Used only if a field name is not set. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java index 0226062d05..cdbb34ee40 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeComponentImpl.java @@ -16,13 +16,13 @@ package ghidra.program.model.data; import java.io.Serializable; +import java.util.Objects; import org.apache.commons.lang3.StringUtils; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsImpl; import ghidra.program.database.data.DataTypeUtilities; -import ghidra.util.SystemUtilities; import ghidra.util.exception.DuplicateNameException; /** @@ -32,7 +32,7 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali private final static long serialVersionUID = 1; private DataType dataType; - private CompositeDataTypeImpl parent; // parent prototype containing us + private CompositeDataTypeImpl parent; // composite containing us (may be null in certain use cases) private int offset; // offset in parent private int ordinal; // position in parent private SettingsImpl defaultSettings; @@ -48,12 +48,11 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali * @param length the length of the dataType in this component. * @param ordinal the index within its parent. * @param offset the byte offset within the parent - * @param fieldName the name associated with this component - * @param comment the comment associated with this component + * @param fieldName the name associated with this component or null + * @param comment the comment associated with this component or null */ public DataTypeComponentImpl(DataType dataType, CompositeDataTypeImpl parent, int length, int ordinal, int offset, String fieldName, String comment) { - this.parent = parent; this.ordinal = ordinal; this.offset = offset; @@ -67,7 +66,7 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali } /** - * Create a new DataTypeComponent + * Create a new DataTypeComponent without a name * @param dataType the dataType for this component * @param parent the dataType that this component belongs to * @param length the length of the dataType in this component. @@ -119,8 +118,9 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali } @Override - public void setComment(String comment) { + public DataTypeComponentImpl setComment(String comment) { this.comment = StringUtils.isBlank(comment) ? null : comment; + return this; } @Override @@ -132,8 +132,10 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali } @Override - public void setFieldName(String name) throws DuplicateNameException { - this.fieldName = InternalDataTypeComponent.cleanupFieldName(name); + public DataTypeComponentImpl setFieldName(String name) { + // Cleanup invalid names and make unique within its parent + fieldName = InternalDataTypeComponent.cleanupFieldName(name); + return this; } public static void checkDefaultFieldName(String fieldName) throws DuplicateNameException { @@ -174,9 +176,9 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali * @param newComment new comment */ void update(String name, DataType newDataType, String newComment) { - this.fieldName = InternalDataTypeComponent.cleanupFieldName(name); this.dataType = newDataType; - this.comment = StringUtils.isBlank(newComment) ? null : newComment; + setFieldName(name); + setComment(newComment); } @Override @@ -220,7 +222,7 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali @Override public Settings getDefaultSettings() { - if (defaultSettings == null) { + if (defaultSettings == null && parent != null) { DataTypeManager dataMgr = parent.getDataTypeManager(); boolean immutableSettings = dataMgr == null || !dataMgr.allowsDefaultComponentSettings(); @@ -251,8 +253,8 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali if (offset != dtc.getOffset() || getLength() != dtc.getLength() || ordinal != dtc.getOrdinal() || - !SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) || - !SystemUtilities.isEqual(getComment(), dtc.getComment())) { + !Objects.equals(getFieldName(), dtc.getFieldName()) || + !Objects.equals(getComment(), dtc.getComment())) { return false; } if (!(myDt instanceof Pointer)) { @@ -291,8 +293,8 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali (myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false; // Components don't need to have matching offset when they are aligned if ((!aligned && (offset != dtc.getOffset())) || - !SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) || - !SystemUtilities.isEqual(getComment(), dtc.getComment())) { + !Objects.equals(getFieldName(), dtc.getFieldName()) || + !Objects.equals(getComment(), dtc.getComment())) { return false; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DialogResourceDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DialogResourceDataType.java index a39a9dde8e..7e8d956a9c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DialogResourceDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DialogResourceDataType.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -126,9 +126,8 @@ public class DialogResourceDataType extends DynamicDataType { private int addDlgTemplateStructure(MemBuffer memBuffer, List comps, int tempOffset, boolean ex) { - tempOffset = - addComp(ex ? dlgTemplateExStructure() : dlgTemplateStructure(), ex ? 26 : 18, - "Dialog Template Structure", memBuffer.getAddress(), comps, tempOffset); + tempOffset = addComp(ex ? dlgTemplateExStructure() : dlgTemplateStructure(), ex ? 26 : 18, + "Dialog Template Structure", memBuffer.getAddress(), comps, tempOffset); return tempOffset; } @@ -139,15 +138,13 @@ public class DialogResourceDataType extends DynamicDataType { short dialogMenuInfo = memBuffer.getShort(tempOffset); if (dialogMenuInfo == 0x0000) { //if 0x0000 - no menu - tempOffset = - addComp(createArrayOfShorts(1), 2, "Dialog Menu", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(1), 2, "Dialog Menu", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } //if 0xFFFF - one more item that is resource number of the menu else if (dialogMenuInfo == 0xFFFF) { - tempOffset = - addComp(createArrayOfShorts(2), 4, "Dialog Menu", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(2), 4, "Dialog Menu", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } //array is unicode name of menu in executable file else { @@ -164,15 +161,13 @@ public class DialogResourceDataType extends DynamicDataType { //if 0x0000 - use predefined class if (dialogClassInfo == 0x0000) { - tempOffset = - addComp(createArrayOfShorts(1), 2, "Dialog Class", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(1), 2, "Dialog Class", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } //if 0xFFFF - one more item that is ordinal value of system window class else if (dialogClassInfo == 0xFFFF) { - tempOffset = - addComp(createArrayOfShorts(2), 4, "Dialog Class", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(2), 4, "Dialog Class", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } //array is unicode name of menu in executable file else { @@ -188,9 +183,8 @@ public class DialogResourceDataType extends DynamicDataType { short dialogTitleInfo = memBuffer.getShort(tempOffset); //if 0x0000 - Dialog has no title if (dialogTitleInfo == 0x0000) { - tempOffset = - addComp(createArrayOfShorts(1), 2, "Dialog Title", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(1), 2, "Dialog Title", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } //array is unicode name of menu in executable file else { @@ -206,22 +200,21 @@ public class DialogResourceDataType extends DynamicDataType { private int addDialogFontComponents(MemBuffer memBuffer, List comps, int tempOffset, boolean ex) { //add Dialog Font size - tempOffset = - addComp(new ShortDataType(), 2, "Dialog Font Size", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(new ShortDataType(), 2, "Dialog Font Size", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); if (ex) { //add Dialog Font weight - tempOffset = addComp(new WordDataType(), 2, "Dialog Font Weight", memBuffer.getAddress().add(tempOffset), - comps, tempOffset); + tempOffset = addComp(new WordDataType(), 2, "Dialog Font Weight", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); //add Dialog Font Italic - tempOffset = addComp(new ByteDataType(), 1, "Dialog Font Italic", memBuffer.getAddress().add(tempOffset), - comps, tempOffset); + tempOffset = addComp(new ByteDataType(), 1, "Dialog Font Italic", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); //add Dialog Font Charset - tempOffset = addComp(new ByteDataType(), 1, "Dialog Font Charset", memBuffer.getAddress().add(tempOffset), - comps, tempOffset); + tempOffset = addComp(new ByteDataType(), 1, "Dialog Font Charset", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } //add Dialog Font Style array @@ -235,9 +228,8 @@ public class DialogResourceDataType extends DynamicDataType { int tempOffset, boolean ex) { if ((memBuffer.getAddress().add(tempOffset).getOffset() % 4) != 0) { - tempOffset = - addComp(new AlignmentDataType(), 2, "Alignment", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(new AlignmentDataType(), 2, "Alignment", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } tempOffset = addComp(ex ? dlgItemTemplateExStructure() : dlgItemTemplateStructure(), ex ? 24 : 18, @@ -247,16 +239,15 @@ public class DialogResourceDataType extends DynamicDataType { } //adds Item class array - 1st after component after each DLGITEMTEMPLATE structure - private int addItemClassArray(MemBuffer memBuffer, List comps, int tempOffset) - throws MemoryAccessException { + private int addItemClassArray(MemBuffer memBuffer, List comps, + int tempOffset) throws MemoryAccessException { short itemClassInfo = memBuffer.getShort(tempOffset); if ((itemClassInfo & 0xffff) == 0xffff) { short classType = memBuffer.getShort(tempOffset + 2); - tempOffset = - addComp(createArrayOfShorts(2), 4, "Item Class Type or Name" + "(" + - getItemType(Integer.valueOf(classType)) + ")", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(2), 4, + "Item Class Type or Name" + "(" + getItemType(Integer.valueOf(classType)) + ")", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } else { tempOffset = addUnicodeString(memBuffer, comps, tempOffset, "Item Class Type or Name"); @@ -265,14 +256,13 @@ public class DialogResourceDataType extends DynamicDataType { } //adds Item title array - 2nd after each DLGITEMTEMPLATE structure - private int addItemTitleArray(MemBuffer memBuffer, List comps, int tempOffset) - throws MemoryAccessException { + private int addItemTitleArray(MemBuffer memBuffer, List comps, + int tempOffset) throws MemoryAccessException { short itemTitleInfo = memBuffer.getShort(tempOffset); if ((itemTitleInfo & 0xffff) == 0xffff) { - tempOffset = - addComp(createArrayOfShorts(2), 4, "Item Title or Resource ID", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(2), 4, "Item Title or Resource ID", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } else { tempOffset = @@ -287,15 +277,13 @@ public class DialogResourceDataType extends DynamicDataType { short itemDataLength = memBuffer.getShort(tempOffset); if (itemDataLength == 0x0000) { - tempOffset = - addComp(createArrayOfShorts(1), 2, "Item Data", - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(createArrayOfShorts(1), 2, "Item Data", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } else { tempOffset = - addComp(new ArrayDataType(ByteDataType.dataType, itemDataLength, 1), - itemDataLength, "Item Data", memBuffer.getAddress().add(tempOffset), comps, - tempOffset); + addComp(new ArrayDataType(ByteDataType.dataType, itemDataLength, 1), itemDataLength, + "Item Data", memBuffer.getAddress().add(tempOffset), comps, tempOffset); } return tempOffset; } @@ -303,154 +291,56 @@ public class DialogResourceDataType extends DynamicDataType { //This is always the first structure in the dialog resource private StructureDataType dlgTemplateExStructure() { StructureDataType struct = new StructureDataType("DLGTEMPLATEEX", 0); - - struct.add(WordDataType.dataType); - struct.add(WordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(WordDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - - try { - struct.getComponent(0).setFieldName("dlgVer"); - struct.getComponent(1).setFieldName("signature"); - struct.getComponent(2).setFieldName("helpId"); - struct.getComponent(3).setFieldName("exStyle"); - struct.getComponent(4).setFieldName("style"); - struct.getComponent(5).setFieldName("cDlgItems"); - struct.getComponent(6).setFieldName("x"); - struct.getComponent(7).setFieldName("y"); - struct.getComponent(8).setFieldName("cx"); - struct.getComponent(9).setFieldName("cy"); - } - catch (DuplicateNameException e) { - Msg.debug(this, "Unexpected exception building DLGTEMPLATEEX", e); - } - struct.getComponent(0).setComment("version (must be 1)"); - struct.getComponent(1).setComment("signature (must be 0xffff)"); - struct.getComponent(2).setComment("help context identifier"); - struct.getComponent(3).setComment("extended styles for a window"); - struct.getComponent(4).setComment("style of dialog box"); - struct.getComponent(5).setComment("number of items in dialog box"); - struct.getComponent(6).setComment("x-coordinate of upper-left corner of dialog"); - struct.getComponent(7).setComment("y-coordinate of upper-left corner of dialog"); - struct.getComponent(8).setComment("width of dialog box"); - struct.getComponent(9).setComment("height of dialog box"); - + struct.add(WordDataType.dataType, "dlgVer", "version (must be 1)"); + struct.add(WordDataType.dataType, "signature", "signature (must be 0xffff)"); + struct.add(DWordDataType.dataType, "helpId", "help context identifier"); + struct.add(DWordDataType.dataType, "exStyle", "extended styles for a window"); + struct.add(DWordDataType.dataType, "style", "style of dialog box"); + struct.add(WordDataType.dataType, "cDlgItems", "number of items in dialog box"); + struct.add(ShortDataType.dataType, "x", "x-coordinate of upper-left corner of dialog"); + struct.add(ShortDataType.dataType, "y", "y-coordinate of upper-left corner of dialog"); + struct.add(ShortDataType.dataType, "cx", "width of dialog box"); + struct.add(ShortDataType.dataType, "cy", "height of dialog box"); return struct; } //This is always the first structure in the dialog resource private StructureDataType dlgTemplateStructure() { StructureDataType struct = new StructureDataType("DLGTEMPLATE", 0); - - struct.add(DWordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(WordDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - - try { - struct.getComponent(0).setFieldName("style"); - struct.getComponent(1).setFieldName("dwExtendedStyle"); - struct.getComponent(2).setFieldName("cdit"); - struct.getComponent(3).setFieldName("x"); - struct.getComponent(4).setFieldName("y"); - struct.getComponent(5).setFieldName("cx"); - struct.getComponent(6).setFieldName("cy"); - } - catch (DuplicateNameException e) { - Msg.debug(this, "Unexpected exception building DLGTEMPLATE", e); - } - struct.getComponent(0).setComment("style of dialog box"); - struct.getComponent(1).setComment("extended styles for a window"); - struct.getComponent(2).setComment("number of items in dialog box"); - struct.getComponent(3).setComment("x-coordinate of upper-left corner of dialog"); - struct.getComponent(4).setComment("y-coordinate of upper-left corner of dialog"); - struct.getComponent(5).setComment("width of dialog box"); - struct.getComponent(6).setComment("height of dialog box"); - + struct.add(DWordDataType.dataType, "style", "style of dialog box"); + struct.add(DWordDataType.dataType, "dwExtendedStyle", "extended styles for a window"); + struct.add(WordDataType.dataType, "cdit", "number of items in dialog box"); + struct.add(ShortDataType.dataType, "x", "x-coordinate of upper-left corner of dialog"); + struct.add(ShortDataType.dataType, "y", "y-coordinate of upper-left corner of dialog"); + struct.add(ShortDataType.dataType, "cx", "width of dialog box"); + struct.add(ShortDataType.dataType, "cy", "height of dialog box"); return struct; } //Each control item has one of these structures private StructureDataType dlgItemTemplateExStructure() { StructureDataType struct = new StructureDataType("DLGITEMTEMPLATEEX", 0); - - try { - struct.add(DWordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(DWordDataType.dataType); - - struct.getComponent(0).setFieldName("helpID"); - struct.getComponent(1).setFieldName("exStyle"); - struct.getComponent(2).setFieldName("style"); - struct.getComponent(3).setFieldName("x"); - struct.getComponent(4).setFieldName("y"); - struct.getComponent(5).setFieldName("cx"); - struct.getComponent(6).setFieldName("cy"); - struct.getComponent(7).setFieldName("id"); - } - catch (DuplicateNameException e) { - Msg.debug(this, "Unexpected exception building DLGITEMTEMPLATEEX", e); - } - - struct.getComponent(0).setComment("help context identifier"); - struct.getComponent(1).setComment("extended styles for a window"); - struct.getComponent(2).setComment("style of control"); - struct.getComponent(3).setComment("x-coordinate of upper-left corner of control"); - struct.getComponent(4).setComment("y-coordinate of upper-left corner of control"); - struct.getComponent(5).setComment("width of control"); - struct.getComponent(6).setComment("height of control"); - struct.getComponent(7).setComment("control identifier"); - + struct.add(DWordDataType.dataType, "helpID", "help context identifier"); + struct.add(DWordDataType.dataType, "exStyle", "extended styles for a window"); + struct.add(DWordDataType.dataType, "style", "style of control"); + struct.add(ShortDataType.dataType, "x", "x-coordinate of upper-left corner of control"); + struct.add(ShortDataType.dataType, "y", "y-coordinate of upper-left corner of control"); + struct.add(ShortDataType.dataType, "cx", "width of control"); + struct.add(ShortDataType.dataType, "cy", "height of control"); + struct.add(DWordDataType.dataType, "id", "control identifier"); return struct; } //Each control item has one of these structures private StructureDataType dlgItemTemplateStructure() { StructureDataType struct = new StructureDataType("DLGITEMTEMPLATE", 0); - - try { - struct.add(DWordDataType.dataType); - struct.add(DWordDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(ShortDataType.dataType); - struct.add(WordDataType.dataType); - - struct.getComponent(0).setFieldName("style"); - struct.getComponent(1).setFieldName("dwExtendedStyle"); - struct.getComponent(2).setFieldName("x"); - struct.getComponent(3).setFieldName("y"); - struct.getComponent(4).setFieldName("cx"); - struct.getComponent(5).setFieldName("cy"); - struct.getComponent(6).setFieldName("id"); - } - catch (DuplicateNameException e) { - Msg.debug(this, "Unexpected exception building DLGITEMTEMPLATE", e); - } - - struct.getComponent(0).setComment("style of control"); - struct.getComponent(1).setComment("extended styles for a window"); - struct.getComponent(2).setComment("x-coordinate of upper-left corner of control"); - struct.getComponent(3).setComment("y-coordinate of upper-left corner of control"); - struct.getComponent(4).setComment("width of control"); - struct.getComponent(5).setComment("height of control"); - struct.getComponent(6).setComment("control identifier"); - + struct.add(DWordDataType.dataType, "style", "style of dialog box"); + struct.add(DWordDataType.dataType, "dwExtendedStyle", "extended styles for a window"); + struct.add(ShortDataType.dataType, "x", "x-coordinate of upper-left corner of control"); + struct.add(ShortDataType.dataType, "y", "y-coordinate of upper-left corner of control"); + struct.add(ShortDataType.dataType, "cx", "width of control"); + struct.add(ShortDataType.dataType, "cy", "height of control"); + struct.add(DWordDataType.dataType, "id", "control identifier"); return struct; } @@ -459,16 +349,15 @@ public class DialogResourceDataType extends DynamicDataType { return itemTypeMap.get(value); } - private int addUnicodeString(MemBuffer memBuffer, List comps, - int tempOffset, String title) { + private int addUnicodeString(MemBuffer memBuffer, List comps, int tempOffset, + String title) { byte[] tempBytes = new byte[1024]; memBuffer.getBytes(tempBytes, tempOffset); int strLength = findUnicodeLength(tempBytes); if (strLength >= 2) { - tempOffset = - addComp(UnicodeDataType.dataType, strLength, title, - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(UnicodeDataType.dataType, strLength, title, + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } return tempOffset; @@ -495,9 +384,8 @@ public class DialogResourceDataType extends DynamicDataType { private int addComp(DataType dataType, int len, String fieldName, Address address, List comps, int currentOffset) { if (len > 0) { - ReadOnlyDataTypeComponent readOnlyDataTypeComponent = - new ReadOnlyDataTypeComponent(dataType, this, len, comps.size(), currentOffset, - fieldName, null); + ReadOnlyDataTypeComponent readOnlyDataTypeComponent = new ReadOnlyDataTypeComponent( + dataType, this, len, comps.size(), currentOffset, fieldName, null); comps.add(readOnlyDataTypeComponent); currentOffset += len; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MenuResourceDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MenuResourceDataType.java index 893951ef7c..c8379ba38a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MenuResourceDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/MenuResourceDataType.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -131,9 +131,8 @@ public class MenuResourceDataType extends DynamicDataType { } //once verified as valid, lay down the initial structure - tempOffset = - addComp(menuItemTemplateHeaderStructure(), 4, "Menu Item Template Header Structure", - memBuffer.getAddress(), comps, tempOffset); + tempOffset = addComp(menuItemTemplateHeaderStructure(), 4, + "Menu Item Template Header Structure", memBuffer.getAddress(), comps, tempOffset); return tempOffset; } @@ -141,21 +140,8 @@ public class MenuResourceDataType extends DynamicDataType { //This is always the first structure in the menu resource private StructureDataType menuItemTemplateHeaderStructure() { StructureDataType struct = new StructureDataType("MENUITEM_TEMPLATE_HEADER", 0); - - struct.add(WordDataType.dataType); - struct.add(WordDataType.dataType); - - try { - struct.getComponent(0).setFieldName("versionNumber"); - struct.getComponent(1).setFieldName("offset"); - - } - catch (DuplicateNameException e) { - Msg.debug(this, "Unexpected exception building MENUITEM_TEMPLATE_HEADER", e); - } - struct.getComponent(0).setComment("Version number of menu"); - struct.getComponent(1).setComment("Menu items offset."); - + struct.add(WordDataType.dataType, "versionNumber", "Version number of menu"); + struct.add(WordDataType.dataType, "offset", "Menu items offset."); return struct; } @@ -165,19 +151,16 @@ public class MenuResourceDataType extends DynamicDataType { //If it is a popup there is only an option field, no ID field if ((mtOption & MF_POPUP) == MF_POPUP) { - tempOffset = - addComp(WordDataType.dataType, 2, "mtOption", memBuffer.getAddress(), comps, - tempOffset); + tempOffset = addComp(WordDataType.dataType, 2, "mtOption", memBuffer.getAddress(), + comps, tempOffset); } //If it is anything else it has option and id fields else { - tempOffset = - addComp(WordDataType.dataType, 2, "mtOption", memBuffer.getAddress(), comps, - tempOffset); + tempOffset = addComp(WordDataType.dataType, 2, "mtOption", memBuffer.getAddress(), + comps, tempOffset); - tempOffset = - addComp(WordDataType.dataType, 2, "mtID", memBuffer.getAddress().add(tempOffset), - comps, tempOffset); + tempOffset = addComp(WordDataType.dataType, 2, "mtID", + memBuffer.getAddress().add(tempOffset), comps, tempOffset); } @@ -189,25 +172,23 @@ public class MenuResourceDataType extends DynamicDataType { private int addComp(DataType dataType, int len, String fieldName, Address address, List comps, int currentOffset) { if (len > 0) { - ReadOnlyDataTypeComponent readOnlyDataTypeComponent = - new ReadOnlyDataTypeComponent(dataType, this, len, comps.size(), currentOffset, - fieldName, null); + ReadOnlyDataTypeComponent readOnlyDataTypeComponent = new ReadOnlyDataTypeComponent( + dataType, this, len, comps.size(), currentOffset, fieldName, null); comps.add(readOnlyDataTypeComponent); currentOffset += len; } return currentOffset; } - private int addUnicodeString(MemBuffer memBuffer, List comps, - int tempOffset, String title) { + private int addUnicodeString(MemBuffer memBuffer, List comps, int tempOffset, + String title) { byte[] tempBytes = new byte[1024]; memBuffer.getBytes(tempBytes, tempOffset); int strLength = findUnicodeLength(tempBytes); if (strLength >= 2) { - tempOffset = - addComp(UnicodeDataType.dataType, strLength, title, - memBuffer.getAddress().add(tempOffset), comps, tempOffset); + tempOffset = addComp(UnicodeDataType.dataType, strLength, title, + memBuffer.getAddress().add(tempOffset), comps, tempOffset); return tempOffset; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ReadOnlyDataTypeComponent.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ReadOnlyDataTypeComponent.java index 6e11ab4524..7704a01f48 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ReadOnlyDataTypeComponent.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ReadOnlyDataTypeComponent.java @@ -101,8 +101,9 @@ public class ReadOnlyDataTypeComponent implements DataTypeComponent, Serializabl } @Override - public void setComment(String comment) { + public DataTypeComponent setComment(String comment) { // ignore - read-only + return this; } @Override @@ -114,8 +115,9 @@ public class ReadOnlyDataTypeComponent implements DataTypeComponent, Serializabl } @Override - public void setFieldName(String fieldName) throws DuplicateNameException { + public DataTypeComponent setFieldName(String fieldName) { // ignore - read-only + return this; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java index 132f68a040..192f1f4493 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java @@ -162,7 +162,8 @@ public interface Structure extends Composite { * @param baseDataType the bitfield base datatype (certain restrictions apply). * @param bitSize the declared bitfield size in bits. The effective bit size may be adjusted * based upon the specified baseDataType. - * @param componentName the field name to associate with this component. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. * @param comment the comment to associate with this component. * @return the bitfield component created whose associated data type will be BitFieldDataType. * @throws InvalidDataTypeException if the specified baseDataType is not a valid base type for @@ -206,7 +207,8 @@ public interface Structure extends Composite { * viewed as big-endian. The final offset may be reduced based upon the minimal * storage size determined during insertion. * @param baseDataType the bitfield base datatype (certain restrictions apply). - * @param componentName the field name to associate with this component. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. * @param bitSize the bitfield size in bits. A bitSize of 0 may be specified although its name * will be ignored. * @param comment the comment to associate with this component. @@ -257,7 +259,8 @@ public interface Structure extends Composite { * structure an {@link Undefined1DataType} will be used in its place. * @param length the length to associate with the dataType. For fixed length types a length * <= 0 will use the length of the resolved dataType. - * @param name the field name to associate with this component. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. * @param comment the comment to associate with this component. * @return the componentDataType created. * @throws IllegalArgumentException if the specified data type is not allowed to be inserted @@ -265,7 +268,8 @@ public interface Structure extends Composite { * suppose dt1 contains dt2. Therefore it is not valid to insert dt1 to dt2 since * this would cause a cyclic dependency. */ - public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, String name, + public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, + String componentName, String comment) throws IllegalArgumentException; /** @@ -383,14 +387,16 @@ public interface Structure extends Composite { * @param length component length for containing the specified dataType. A positive length is required * for sizable {@link Dynamic} datatypes and should be specified as -1 for fixed-length * datatypes to rely on their resolved size. - * @param name the field name to associate with this component or null. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. * @param comment the comment to associate with this component or null. * @return the new component. * @throws IllegalArgumentException may be caused by: 1) invalid offset specified, 2) invalid datatype or * associated length specified, or 3) insufficient space for replacement. * @throws IndexOutOfBoundsException if component ordinal is out of bounds */ - public DataTypeComponent replace(int ordinal, DataType dataType, int length, String name, + public DataTypeComponent replace(int ordinal, DataType dataType, int length, + String componentName, String comment) throws IndexOutOfBoundsException, IllegalArgumentException; /** @@ -428,13 +434,15 @@ public interface Structure extends Composite { * @param length component length for containing the specified dataType. A positive length is required * for sizable {@link Dynamic} datatypes and should be specified as -1 for fixed-length * datatypes to rely on their resolved size. - * @param name the field name to associate with this component or null. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. * @param comment the comment to associate with this component or null. * @return the new component. * @throws IllegalArgumentException may be caused by: 1) invalid offset specified, 2) invalid datatype or * associated length specified, or 3) insufficient space for replacement. */ - public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length, String name, + public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length, + String componentName, String comment) throws IllegalArgumentException; /** diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java index 53119e1ed1..94193ea48d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java @@ -16,6 +16,7 @@ package ghidra.program.model.data; import java.util.*; +import java.util.function.Consumer; import ghidra.docking.settings.Settings; import ghidra.program.database.data.DataTypeUtilities; @@ -26,13 +27,8 @@ import ghidra.util.exception.AssertException; /** * Basic implementation of the structure data type. - * NOTES: - *

    - *
  • Implementation is not thread safe when being modified.
  • - *
  • For a structure to treated as having a zero-length (see {@link #isZeroLength()}) it
  • - * - *
- * + *

+ * NOTE: Implementation is not thread safe. */ public class StructureDataType extends CompositeDataTypeImpl implements StructureInternal { @@ -386,6 +382,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur } } if (nextOrdinal != null && nextOrdinal == ordinal) { + // defined component removed if (dtc.isBitFieldComponent()) { // defer reconciling bitfield space to repack @@ -394,12 +391,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur else { offsetAdjustment -= dtc.getLength(); } + dtc.getDataType().removeParent(this); + --ordinalAdjustment; lastDefinedOrdinal = ordinal; nextOrdinal = sortedOrdinals.higher(ordinal); } else { - if (ordinalAdjustment != 0) { shiftOffset(dtc, ordinalAdjustment, offsetAdjustment); } @@ -565,11 +563,14 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur return new DataTypeComponentImpl(DataType.DEFAULT, this, 1, ordinal, offset); } - DataTypeComponentImpl dtc = new DataTypeComponentImpl(dataType, this, length, ordinal, + length = getPreferredComponentLength(dataType, length); + + DataTypeComponentImpl dtc = createComponent(dataType, length, ordinal, offset, componentName, comment); dataType.addParent(this); shiftOffsets(index, 1 + additionalShift, length + additionalShift); components.add(index, dtc); + repack(false); notifySizeChanged(); return dtc; @@ -622,12 +623,12 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur DataTypeComponentImpl dtc; if (dataType == DataType.DEFAULT) { - // assume non-packed structure - structre will grow by 1-byte below + // assume non-packed structure - will grow by 1-byte below dtc = new DataTypeComponentImpl(DataType.DEFAULT, this, 1, numComponents, structLength); } else { int componentLength = getPreferredComponentLength(dataType, length); - dtc = new DataTypeComponentImpl(dataType, this, componentLength, numComponents, + dtc = createComponent(dataType, componentLength, numComponents, structLength, componentName, comment); dataType.addParent(this); components.add(dtc); @@ -667,9 +668,14 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur } else { index = backupToFirstComponentContainingOffset(index, len); + index = afterNonZeroComponentsAtOffset(index, len); } int definedComponentCount = components.size(); if (index >= 0 && index < definedComponentCount) { + // Process deleted components + components.subList(index, components.size()).forEach(dtc -> { + dtc.getDataType().removeParent(this); + }); components = components.subList(0, index); } } @@ -743,11 +749,12 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur length = getPreferredComponentLength(dataType, length); int offset = (getComponent(ordinal)).getOffset(); - DataTypeComponentImpl dtc = new DataTypeComponentImpl(dataType, this, length, ordinal, + DataTypeComponentImpl dtc = createComponent(dataType, length, ordinal, offset, componentName, comment); dataType.addParent(this); shiftOffsets(idx, 1, dtc.getLength()); components.add(idx, dtc); + repack(false); notifySizeChanged(); return dtc; @@ -901,11 +908,11 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur BitFieldDataType bitfieldDt = new BitFieldDataType(baseDataType, bitSize, storageBitOffset); - DataTypeComponentImpl dtc = new DataTypeComponentImpl(bitfieldDt, this, + DataTypeComponentImpl dtc = createComponent(bitfieldDt, bitfieldDt.getStorageSize(), ordinal, revisedOffset, componentName, comment); bitfieldDt.addParent(this); // currently has no affect - components.add(startIndex, dtc); + adjustNonPackedComponents(); notifySizeChanged(); return dtc; @@ -1259,6 +1266,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur /** * Replaces the internal components of this structure with components of the given structure * including packing and alignment settings. + *

+ * NOTE: unlike adding new components which will guarantee component name uniqueness, this + * method will preserve component names. * * @param dataType the structure to get the component information from. * @throws IllegalArgumentException if any of the component data types are not allowed to @@ -1274,6 +1284,12 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur } try { + + // Remove all existing components + for (DataTypeComponentImpl dtc : components) { + dtc.getDataType().removeParent(this); + } + components.clear(); numComponents = 0; structLength = 0; @@ -1341,8 +1357,11 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur length = getPreferredComponentLength(dt, -1, maxLength); } - components.add(new DataTypeComponentImpl(dt, this, length, dtc.getOrdinal(), - dtc.getOffset(), dtc.getFieldName(), dtc.getComment())); + // Note: original component name is preserved + DataTypeComponentImpl newDtc = createComponent(dt, length, dtc.getOrdinal(), + dtc.getOffset(), dtc.getFieldName(), dtc.getComment()); + dt.addParent(this); + components.add(newDtc); } } @@ -1431,7 +1450,12 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur @Override public DataTypeComponent[] getDefinedComponents() { - return components.toArray(new DataTypeComponent[components.size()]); + return components.toArray(new DataTypeComponentImpl[components.size()]); + } + + @Override + void forEachDefinedComponent(Consumer dtcConsumer) { + components.forEach(dtcConsumer); } @Override @@ -1481,7 +1505,8 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur } @Override - public final DataTypeComponent replace(int index, DataType dataType, int length) { + public final DataTypeComponent replace(int index, DataType dataType, int length) + throws IndexOutOfBoundsException, IllegalArgumentException { return replace(index, dataType, length, null, null); } @@ -1792,9 +1817,10 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur DataTypeComponentImpl newDtc = null; if (!clearOnly) { // insert new component - newDtc = new DataTypeComponentImpl(dataType, this, length, newOrdinal, newOffset, - fieldName, comment); + newDtc = + createComponent(dataType, length, newOrdinal, newOffset, fieldName, comment); components.add(index, newDtc); + dataType.addParent(this); } // adjust ordinals of trailing components - defer if packing is enabled diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Union.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Union.java index cfbefb8784..6b12efcf9b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Union.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Union.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -37,7 +37,8 @@ public interface Union extends Composite { * @param baseDataType the bitfield base datatype (certain restrictions apply). * @param bitSize the declared bitfield size in bits. The effective bit size may be * adjusted based upon the specified baseDataType. - * @param componentName the field name to associate with this component. + * @param componentName the field name to associate with this component. (may be null) + * The name may be sanitized to convert all whitespace characters to an underscore. * @param comment the comment to associate with this component. * @return the bitfield component created whose associated data type will * be BitFieldDataType. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnionDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnionDataType.java index 94ae985871..7d1192c4c7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnionDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/UnionDataType.java @@ -16,6 +16,7 @@ package ghidra.program.model.data; import java.util.*; +import java.util.function.Consumer; import ghidra.docking.settings.Settings; import ghidra.program.database.data.DataTypeUtilities; @@ -24,7 +25,8 @@ import ghidra.util.UniversalID; /** * Basic implementation of the union data type. - * NOTE: Implementation is not thread safe when being modified. + *

+ * NOTE: Implementation is not thread safe. */ public class UnionDataType extends CompositeDataTypeImpl implements UnionInternal { @@ -116,6 +118,11 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna return getComponents(); } + @Override + void forEachDefinedComponent(Consumer dtcConsumer) { + components.forEach(dtcConsumer); + } + @Override public int getNumComponents() { return components.size(); @@ -134,6 +141,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna int oldAlignment = getAlignment(); DataTypeComponent dtc = doAdd(dataType, length, componentName, comment); + if (!repack(true) && isPackingEnabled() && oldAlignment != getAlignment()) { notifyAlignmentChanged(); } @@ -163,8 +171,8 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna return length; } - DataTypeComponentImpl doAdd(DataType dataType, int length, String componentName, String comment) - throws DataTypeDependencyException { + DataTypeComponentImpl doAdd(DataType dataType, int length, String componentName, + String comment) throws DataTypeDependencyException { dataType = validateDataType(dataType); @@ -175,8 +183,9 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna length = getPreferredComponentLength(dataType, length); - DataTypeComponentImpl dtc = new DataTypeComponentImpl(dataType, this, length, + DataTypeComponentImpl dtc = createComponent(dataType, length, components.size(), 0, componentName, comment); + dataType.addParent(this); components.add(dtc); @@ -198,7 +207,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna length = getPreferredComponentLength(dataType, length); - DataTypeComponentImpl dtc = new DataTypeComponentImpl(dataType, this, length, ordinal, + DataTypeComponentImpl dtc = createComponent(dataType, length, ordinal, 0, componentName, comment); dataType.addParent(this); shiftOrdinals(ordinal, 1); @@ -311,6 +320,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna if (ordinals.contains(ordinal)) { // component removed --ordinalAdjustment; + dtc.getDataType().removeParent(this); } else { if (ordinalAdjustment != 0) { diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java index d91bc81946..c4f12021cc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/StructureDBTest.java @@ -134,6 +134,7 @@ public class StructureDBTest extends AbstractGenericTest { assertEquals("field1", dtc.getFieldName()); assertEquals("Comment1", dtc.getComment()); assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + assertEquals(dtc, struct.findComponent("field1")); dtc = struct.getComponent(1); assertEquals(1, dtc.getOffset()); @@ -148,6 +149,7 @@ public class StructureDBTest extends AbstractGenericTest { assertEquals("field3", dtc.getFieldName()); assertEquals(null, dtc.getComment()); assertEquals(DWordDataType.class, dtc.getDataType().getClass()); + assertEquals(dtc, struct.findComponent("field3")); dtc = struct.getComponent(3); assertEquals(7, dtc.getOffset()); @@ -155,7 +157,23 @@ public class StructureDBTest extends AbstractGenericTest { assertEquals("field4", dtc.getFieldName()); assertEquals("Comment4", dtc.getComment()); assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + assertEquals(dtc, struct.findComponent("field4")); + dtc = struct.add(ByteDataType.dataType, "field3", "new comment"); + assertEquals(8, dtc.getOffset()); + assertEquals(4, dtc.getOrdinal()); + assertEquals("field3", dtc.getFieldName()); + assertEquals("new comment", dtc.getComment()); + assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + assertNotNull(struct.findComponent("field3")); // which one is returned is arbitrary + + dtc = struct.add(ByteDataType.dataType, "field3 1", "new comment"); // cleanup required + assertEquals(9, dtc.getOffset()); + assertEquals(5, dtc.getOrdinal()); + assertEquals("field3_1", dtc.getFieldName()); + assertEquals("new comment", dtc.getComment()); + assertEquals(ByteDataType.class, dtc.getDataType().getClass()); + assertEquals(dtc, struct.findComponent("field3_1")); // name gets modified } @Test @@ -1869,7 +1887,7 @@ public class StructureDBTest extends AbstractGenericTest { } @Test - public void testDelete() throws InvalidDataTypeException { + public void testDeleteBF() throws InvalidDataTypeException { struct.insertBitFieldAt(2, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment"); struct.insertBitFieldAt(2, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment"); @@ -1911,8 +1929,12 @@ public class StructureDBTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf2")); + struct.delete(3); + assertNull(struct.findComponent("bf2")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/Test\n" + "pack(disabled)\n" + @@ -1928,8 +1950,12 @@ public class StructureDBTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf3")); + struct.delete(3); + assertNull(struct.findComponent("bf3")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/Test\n" + "pack(disabled)\n" + @@ -1945,8 +1971,12 @@ public class StructureDBTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf4")); + struct.delete(4); + assertNull(struct.findComponent("bf4")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/Test\n" + "pack(disabled)\n" + @@ -1963,8 +1993,12 @@ public class StructureDBTest extends AbstractGenericTest { "Length: 11 Alignment: 1", struct); //@formatter:on + assertNotNull(struct.findComponent("bf1")); + struct.delete(2); + assertNull(struct.findComponent("bf1")); + //@formatter:off CompositeTestUtils.assertExpectedComposite(this, "/Test\n" + "pack(disabled)\n" + @@ -2092,7 +2126,7 @@ public class StructureDBTest extends AbstractGenericTest { } @Test - public void testDeleteComponent() { + public void testDataTypeDeleted() { Structure s = new StructureDataType("test1", 0); s.add(new ByteDataType()); s.add(new FloatDataType()); @@ -2149,6 +2183,21 @@ public class StructureDBTest extends AbstractGenericTest { assertEquals(0, s.getNumComponents()); } + @Test + public void testGetComponentByName() { + DataTypeComponent dtc = struct.findComponent("field1"); + assertNotNull(dtc); + assertEquals("field1", dtc.getFieldName()); + + dtc = struct.findComponent("field3"); + assertNotNull(dtc); + assertEquals("field3", dtc.getFieldName()); + + dtc = struct.findComponent("field4"); + assertNotNull(dtc); + assertEquals("field4", dtc.getFieldName()); + } + @Test public void testGetComponentAt() { /** diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java index 393993e4ae..f773f889b2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/database/data/UnionDBTest.java @@ -745,4 +745,63 @@ public class UnionDBTest extends AbstractGenericTest { "Should be able to insert a union typedef array pointer into the pointer's union."); } } + + @Test + public void testFieldNameWhitespaceConvertedToUnderscores() { + UnionDataType newUnion = new UnionDataType("Test"); + DataTypeComponent component = newUnion.add(new ByteDataType(), " name with spaces", null); + assertEquals("name_with_spaces", component.getFieldName()); + + union = (UnionDB) dataMgr.resolve(newUnion, null); + + component = union.getComponent(0); + component.setFieldName(" name in db with spaces "); + assertEquals("name_in_db_with_spaces", component.getFieldName()); + + component = union.add(new ByteDataType(), " another test ", null); + assertEquals("another_test", component.getFieldName()); + + union.insert(0, new ByteDataType(), 1, " insert test ", ""); + component = union.getComponent(0); + assertEquals("insert_test", component.getFieldName()); + + union.insert(1, new ByteDataType(), 1, " insert test ", ""); + component = union.getComponent(1); + assertEquals("insert_test", component.getFieldName()); + } + + @Test + public void testDefaultFieldNames() { + UnionDataType newUnion = new UnionDataType("Test"); + DataTypeComponent component = newUnion.add(new ByteDataType(), " ", null); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + + union = (UnionDB) dataMgr.resolve(newUnion, null); + + component = union.add(new ByteDataType(), null, null); + assertNull(component.getFieldName()); + assertEquals("field1", component.getDefaultFieldName()); + + component = union.getComponent(0); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + + component.setFieldName(" "); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + + component = union.add(new ByteDataType(), null, null); + assertNull(component.getFieldName()); + assertEquals("field2", component.getDefaultFieldName()); + + component = union.add(new ByteDataType(), " ", null); + assertNull(component.getFieldName()); + assertEquals("field3", component.getDefaultFieldName()); + + union.insert(0, new ByteDataType(), 1, null, ""); + component = union.getComponent(0); + assertNull(component.getFieldName()); + assertEquals("field0", component.getDefaultFieldName()); + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/CompositeTestUtils.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/CompositeTestUtils.java index f3f090a21e..facc5e8e57 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/CompositeTestUtils.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/CompositeTestUtils.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -77,7 +77,7 @@ public class CompositeTestUtils { if (mismatch) { Msg.error(test, "Expected composite:\n" + expectedDump); Msg.error(test, "Result composite:\n" + result); - fail("Failed to parse expected composite (see log)"); + fail("Composite mismatch (see log)"); } }