diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java index ab76cefdf2..5f88476f7a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java @@ -1365,7 +1365,13 @@ class StructureEditorModel extends CompEditorModel { if (numComps > 0) { // Remove the structure. int currentOffset = currentComp.getOffset(); - deleteComponent(rowIndex); // TODO: Should clear for non-packed + + // NOTE: There is still a case which is unhandled: if there is a zero-length + // component at the same offset as the component to be unpacked, the unpacking + // will be inserted before the zero-length component. More work is needed to + // handle this case. + + deleteComponent(rowIndex); // Add the structure's elements Stack zeroDtcStack = new Stack<>(); @@ -1379,6 +1385,7 @@ class StructureEditorModel extends CompEditorModel { int compOffset = dtc.getOffset(); if (compOffset != zeroStackOffset && !zeroDtcStack.isEmpty()) { + packedOrdinal += zeroDtcStack.size(); applyZeroDtcStack(viewStruct, currentOffset, componentOrdinal, zeroDtcStack, zeroStackOffset, zeroStackOrdinal); } @@ -1443,7 +1450,9 @@ class StructureEditorModel extends CompEditorModel { private void applyZeroDtcStack(Structure viewStruct, int unpackOffset, int unpackOrdinal, Stack zeroDtcStack, int zeroStackOffset, int zeroStackOrdinal) { - zeroDtcStack.forEach(zeroDtc -> { + + while (!zeroDtcStack.isEmpty()) { + DataTypeComponent zeroDtc = zeroDtcStack.pop(); if (!isPackingEnabled()) { viewStruct.insertAtOffset(unpackOffset + zeroStackOffset, zeroDtc.getDataType(), 0, zeroDtc.getFieldName(), zeroDtc.getComment()); @@ -1452,7 +1461,7 @@ class StructureEditorModel extends CompEditorModel { viewStruct.insert(unpackOrdinal + zeroStackOrdinal, zeroDtc.getDataType(), 0, zeroDtc.getFieldName(), zeroDtc.getComment()); } - }); + } zeroDtcStack.clear(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java index 65e191d16a..252f24b921 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java @@ -24,6 +24,8 @@ import docking.ActionContext; import docking.action.KeyBindingData; import docking.widgets.OptionDialog; import generic.theme.GIcon; +import ghidra.program.model.data.DataTypeComponent; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskLauncher; @@ -53,9 +55,23 @@ public class UnpackageAction extends CompositeEditorTableAction { if (!isEnabledForContext(context)) { return; } + // If lots of components, verify the user really wants to unpackage. int currentRowIndex = model.getSelection().getFieldRange(0).getStart().getIndex().intValue(); + + // Check for unsupported unpack case. + StructureEditorModel structModel = (StructureEditorModel) model; + if (!structModel.isPackingEnabled()) { + DataTypeComponent dtc = structModel.getComponent(currentRowIndex); + if (dtc != null && dtc.getOrdinal() != 0 && + structModel.getComponent(currentRowIndex - 1).getOffset() == dtc.getOffset()) { + Msg.showInfo(this, model.getProvider().getComponent(), "Unsupported Unpack", + "Unpack is not supported when component offset is shared with a zero-length component."); + return; + } + } + int subComps = model.getNumSubComponents(currentRowIndex); if (subComps > 1000) { String question = "Are you sure you want to unpackage " + subComps + " components?";