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 8530215c53a..74eefed2e90 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 @@ -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. @@ -345,6 +345,11 @@ protected void doSetNameRecord(String name) throws IOException { compositeAdapter.updateRecord(record, true); } + protected void removeComponentRecord(long compKey) throws IOException { + componentAdapter.removeRecord(compKey); + dataMgr.getSettingsAdapter().removeAllSettingsRecords(compKey); + } + /** * This method throws an exception if the indicated data type is not a valid * data type for a component of this composite data type. If the DEFAULT 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 6b3f198815e..59ba1ec41e4 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 @@ -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. @@ -544,20 +544,29 @@ public void delete(int ordinal) { } /** - * Removes a defined component at the specified index without any alteration to other components. + * 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. * @param index defined component index * @return the defined component which was removed. * @throws IOException if an IO error occurs */ private DataTypeComponentDB doDelete(int index) throws IOException { DataTypeComponentDB dtc = components.remove(index); - dtc.getDataType().removeParent(this); - long compKey = dtc.getKey(); - componentAdapter.removeRecord(compKey); - dataMgr.getSettingsAdapter().removeAllSettingsRecords(compKey); + doDelete(dtc); 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. *

@@ -587,38 +596,53 @@ private void doDeleteWithComponentShift(int index, boolean disableOffsetShift) { @Override public void delete(Set ordinals) { + + if (ordinals.isEmpty()) { + return; + } + + if (ordinals.size() == 1) { + ordinals.forEach(ordinal -> delete(ordinal)); + return; + } + lock.acquire(); try { checkDeleted(); - if (ordinals.isEmpty()) { - return; + TreeSet sortedOrdinals = new TreeSet<>(ordinals); + int firstOrdinal = sortedOrdinals.first(); + int lastOrdinal = sortedOrdinals.last(); + if (firstOrdinal < 0 || lastOrdinal >= numComponents) { + throw new IndexOutOfBoundsException(ordinals.size() + " ordinals specified"); } - boolean bitFieldRemoved = false; - - TreeSet treeSet = null; - if (!isPackingEnabled()) { - // treeSet only used to track undefined filler removal - treeSet = new TreeSet<>(ordinals); - } + Integer nextOrdinal = firstOrdinal; - List newComponents = new ArrayList<>(); int ordinalAdjustment = 0; int offsetAdjustment = 0; int lastDefinedOrdinal = -1; + + boolean isPacked = isPackingEnabled(); + + boolean bitFieldRemoved = false; + + List newComponents = new ArrayList<>(components.size()); + for (DataTypeComponentDB dtc : components) { int ordinal = dtc.getOrdinal(); - if (treeSet != null && lastDefinedOrdinal < (ordinal - 1)) { + if (!isPacked && nextOrdinal != null && nextOrdinal < ordinal) { // Identify removed filler since last defined component - Set removedFillerSet = treeSet.subSet(lastDefinedOrdinal + 1, ordinal); + SortedSet removedFillerSet = + sortedOrdinals.subSet(lastDefinedOrdinal + 1, ordinal); if (!removedFillerSet.isEmpty()) { int undefinedRemoveCount = removedFillerSet.size(); ordinalAdjustment -= undefinedRemoveCount; offsetAdjustment -= undefinedRemoveCount; + nextOrdinal = sortedOrdinals.higher(removedFillerSet.last()); } } - if (ordinals.contains(ordinal)) { + if (nextOrdinal != null && nextOrdinal == ordinal) { // defined component removed if (dtc.isBitFieldComponent()) { // defer reconciling bitfield space to repack @@ -627,8 +651,10 @@ public void delete(Set ordinals) { else { offsetAdjustment -= dtc.getLength(); } + doDelete(dtc); // delete defined component record --ordinalAdjustment; lastDefinedOrdinal = ordinal; + nextOrdinal = sortedOrdinals.higher(ordinal); } else { if (ordinalAdjustment != 0) { @@ -638,10 +664,10 @@ public void delete(Set ordinals) { lastDefinedOrdinal = ordinal; } } - if (treeSet != null) { + if (!isPacked) { // Identify removed filler after last defined component Set removedFillerSet = - treeSet.subSet(lastDefinedOrdinal + 1, numComponents); + sortedOrdinals.subSet(lastDefinedOrdinal + 1, numComponents); if (!removedFillerSet.isEmpty()) { int undefinedRemoveCount = removedFillerSet.size(); ordinalAdjustment -= undefinedRemoveCount; @@ -653,7 +679,7 @@ public void delete(Set ordinals) { components = newComponents; updateComposite(numComponents + ordinalAdjustment, -1, -1, true); - if (isPackingEnabled()) { + if (isPacked) { if (!repack(false, true)) { dataMgr.dataTypeChanged(this, false); } @@ -667,6 +693,9 @@ public void delete(Set ordinals) { notifySizeChanged(false); } } + catch (IOException e) { + dataMgr.dbError(e); + } finally { lock.release(); } @@ -1684,9 +1713,9 @@ private void doReplaceWithPacked(Structure struct, DataType[] resolvedDts) { private void doReplaceWithNonPacked(Structure struct, DataType[] resolvedDts) throws IOException { - + // caller responsible for record updates - + // assumes components is clear and that alignment characteristics have been set. if (struct.isNotYetDefined()) { return; @@ -2486,9 +2515,8 @@ private boolean updateComposite(int currentNumComponents, int currentLength, record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, structLength); compositeChanged = true; } - if (currentAlignment >= 0 && - (currentAlignment != structAlignment || currentAlignment != record - .getIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL))) { + if (currentAlignment >= 0 && (currentAlignment != structAlignment || + currentAlignment != record.getIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL))) { structAlignment = currentAlignment; record.setIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL, structAlignment); compositeChanged = true; 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 eb989d4d09d..db0ffb23a2d 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 @@ -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. @@ -159,16 +159,6 @@ private DataTypeComponentDB createComponent(long dtID, int length, int ordinal, return null; } - private void removeComponent(long compKey) { - try { - componentAdapter.removeRecord(compKey); - dataMgr.getSettingsAdapter().removeAllSettingsRecords(compKey); - } - catch (IOException e) { - dataMgr.dbError(e); - } - } - @Override public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name, String comment) throws IllegalArgumentException { @@ -234,13 +224,16 @@ public void delete(int ordinal) { DataTypeComponentDB dtc = components.remove(ordinal); dtc.getDataType().removeParent(this); - removeComponent(dtc.getKey()); + removeComponentRecord(dtc.getKey()); shiftOrdinals(ordinal, -1); if (!repack(false, true)) { dataMgr.dataTypeChanged(this, false); } } + catch (IOException e) { + dataMgr.dbError(e); + } finally { lock.release(); } @@ -248,10 +241,16 @@ public void delete(int ordinal) { @Override public void delete(Set ordinals) { + if (ordinals.isEmpty()) { return; } + if (ordinals.size() == 1) { + ordinals.forEach(ordinal -> delete(ordinal)); + return; + } + lock.acquire(); try { checkDeleted(); @@ -266,7 +265,9 @@ public void delete(Set ordinals) { for (DataTypeComponentDB dtc : components) { int ordinal = dtc.getOrdinal(); if (ordinals.contains(ordinal)) { - // component removed + // component removed - delete record + dtc.getDataType().removeParent(this); + removeComponentRecord(dtc.getKey()); --ordinalAdjustment; } else { @@ -285,10 +286,24 @@ public void delete(Set ordinals) { } } else { - unionLength = newLength; - notifySizeChanged(false); + boolean sizeChanged = (unionLength != newLength); + if (sizeChanged) { + unionLength = newLength; + record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, unionLength); + } + compositeAdapter.updateRecord(record, true); + + if (sizeChanged) { + notifySizeChanged(false); + } + else { + dataMgr.dataTypeChanged(this, false); + } } } + catch (IOException e) { + dataMgr.dbError(e); + } finally { lock.release(); } @@ -332,7 +347,7 @@ void doReplaceWith(UnionInternal union, boolean notify) for (DataTypeComponentDB dtc : components) { dtc.getDataType().removeParent(this); - removeComponent(dtc.getKey()); + removeComponentRecord(dtc.getKey()); } components.clear(); unionAlignment = -1; @@ -708,7 +723,7 @@ public void dataTypeDeleted(DataType dt) { if (removeBitFieldComponent || dtc.getDataType() == dt) { dt.removeParent(this); components.remove(i); - removeComponent(dtc.getKey()); + removeComponentRecord(dtc.getKey()); shiftOrdinals(i, -1); changed = true; } @@ -717,6 +732,9 @@ public void dataTypeDeleted(DataType dt) { dataMgr.dataTypeChanged(this, false); } } + catch (IOException e) { + dataMgr.dbError(e); + } finally { lock.release(); } @@ -853,7 +871,7 @@ else if (dtc.getDataType() == oldDt) { if (remove) { oldDt.removeParent(this); components.remove(i); - removeComponent(dtc.getKey()); + removeComponentRecord(dtc.getKey()); shiftOrdinals(i, -1); changed = true; } 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 67202c20465..bc002ee434f 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 @@ -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. @@ -348,30 +348,44 @@ public void delete(Set ordinals) { return; } - boolean bitFieldRemoved = false; + if (ordinals.size() == 1) { + ordinals.forEach(ordinal -> delete(ordinal)); + return; + } - TreeSet treeSet = null; - if (!isPackingEnabled()) { - // treeSet only used to track undefined filler removal - treeSet = new TreeSet<>(ordinals); + TreeSet sortedOrdinals = new TreeSet<>(ordinals); + int firstOrdinal = sortedOrdinals.first(); + int lastOrdinal = sortedOrdinals.last(); + if (firstOrdinal < 0 || lastOrdinal >= numComponents) { + throw new IndexOutOfBoundsException(ordinals.size() + " ordinals specified"); } - List newComponents = new ArrayList<>(); + Integer nextOrdinal = firstOrdinal; + int ordinalAdjustment = 0; int offsetAdjustment = 0; int lastDefinedOrdinal = -1; + + boolean isPacked = isPackingEnabled(); + + boolean bitFieldRemoved = false; + + List newComponents = new ArrayList<>(components.size()); + for (DataTypeComponentImpl dtc : components) { int ordinal = dtc.getOrdinal(); - if (treeSet != null && lastDefinedOrdinal < (ordinal - 1)) { + if (!isPacked && nextOrdinal != null && nextOrdinal < ordinal) { // Identify removed filler since last defined component - Set removedFillerSet = treeSet.subSet(lastDefinedOrdinal + 1, ordinal); + SortedSet removedFillerSet = + sortedOrdinals.subSet(lastDefinedOrdinal + 1, ordinal); if (!removedFillerSet.isEmpty()) { int undefinedRemoveCount = removedFillerSet.size(); ordinalAdjustment -= undefinedRemoveCount; offsetAdjustment -= undefinedRemoveCount; + nextOrdinal = sortedOrdinals.higher(removedFillerSet.last()); } } - if (ordinals.contains(ordinal)) { + if (nextOrdinal != null && nextOrdinal == ordinal) { // defined component removed if (dtc.isBitFieldComponent()) { // defer reconciling bitfield space to repack @@ -382,6 +396,7 @@ public void delete(Set ordinals) { } --ordinalAdjustment; lastDefinedOrdinal = ordinal; + nextOrdinal = sortedOrdinals.higher(ordinal); } else { @@ -392,9 +407,10 @@ public void delete(Set ordinals) { lastDefinedOrdinal = ordinal; } } - if (treeSet != null) { + if (!isPacked) { // Identify removed filler after last defined component - Set removedFillerSet = treeSet.subSet(lastDefinedOrdinal + 1, numComponents); + Set removedFillerSet = + sortedOrdinals.subSet(lastDefinedOrdinal + 1, numComponents); if (!removedFillerSet.isEmpty()) { int undefinedRemoveCount = removedFillerSet.size(); ordinalAdjustment -= undefinedRemoveCount; @@ -405,7 +421,7 @@ public void delete(Set ordinals) { components = newComponents; numComponents += ordinalAdjustment; - if (isPackingEnabled()) { + if (isPacked) { repack(true); } else { 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 af3f5d054ce..75f2a5419b5 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 @@ -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. @@ -286,6 +286,11 @@ public void delete(Set ordinals) { return; } + if (ordinals.size() == 1) { + ordinals.forEach(ordinal -> delete(ordinal)); + return; + } + int oldAlignment = getAlignment(); List newComponents = new ArrayList<>(); @@ -312,7 +317,7 @@ public void delete(Set ordinals) { notifyAlignmentChanged(); } } - else { + else if (unionLength != newLength) { unionLength = newLength; notifySizeChanged(); }