16
16
package ghidra .program .database .data ;
17
17
18
18
import java .io .IOException ;
19
- import java .util .List ;
20
- import java .util .Map ;
19
+ import java .util .*;
21
20
import java .util .concurrent .ConcurrentHashMap ;
22
21
23
22
import db .Record ;
26
25
import ghidra .program .model .data .*;
27
26
import ghidra .program .model .data .DataTypeConflictHandler .ConflictResult ;
28
27
import ghidra .util .InvalidNameException ;
28
+ import ghidra .util .Lock ;
29
29
import ghidra .util .exception .AssertException ;
30
30
import ghidra .util .exception .DuplicateNameException ;
31
31
import ghidra .util .task .TaskMonitor ;
@@ -41,6 +41,7 @@ class CategoryDB extends DatabaseObject implements Category {
41
41
42
42
private LazyLoadingCachingMap <String , CategoryDB > subcategoryMap ;
43
43
private LazyLoadingCachingMap <String , DataType > dataTypeMap ;
44
+ private ConflictMap conflictMap ;
44
45
45
46
/**
46
47
* Category Constructor
@@ -57,19 +58,19 @@ class CategoryDB extends DatabaseObject implements Category {
57
58
this .name = name ;
58
59
this .parent = parent ;
59
60
60
- subcategoryMap = new LazyLoadingCachingMap <>(mgr .lock , CategoryDB . class ) {
61
+ subcategoryMap = new LazyLoadingCachingMap <>(mgr .lock ) {
61
62
@ Override
62
63
public Map <String , CategoryDB > loadMap () {
63
64
return buildSubcategoryMap ();
64
65
}
65
66
};
66
- dataTypeMap = new LazyLoadingCachingMap <>(mgr .lock , DataType . class ) {
67
+ dataTypeMap = new LazyLoadingCachingMap <>(mgr .lock ) {
67
68
@ Override
68
69
public Map <String , DataType > loadMap () {
69
70
return createDataTypeMap ();
70
71
}
71
72
};
72
-
73
+ conflictMap = new ConflictMap ( mgr . lock );
73
74
}
74
75
75
76
/**
@@ -102,6 +103,7 @@ protected boolean refresh() {
102
103
protected boolean refresh (Record rec ) {
103
104
subcategoryMap .clear ();
104
105
dataTypeMap .clear ();
106
+ conflictMap .clear ();
105
107
106
108
if (isRoot ()) {
107
109
return true ;
@@ -210,13 +212,26 @@ private Map<String, DataType> createDataTypeMap() {
210
212
return map ;
211
213
}
212
214
215
+ private String getBaseName (String dataTypeName ) {
216
+ int indexOf = dataTypeName .indexOf (DataType .CONFLICT_SUFFIX );
217
+ if (indexOf <= 0 ) {
218
+ return dataTypeName ;
219
+ }
220
+ return dataTypeName .substring (0 , indexOf );
221
+ }
222
+
223
+ private boolean isConflictName (String dataTypeName ) {
224
+ return dataTypeName .contains (DataType .CONFLICT_SUFFIX );
225
+ }
226
+
213
227
/**
214
228
* @see ghidra.program.model.data.Category#getCategories()
215
229
*/
216
230
@ Override
217
231
public Category [] getCategories () {
218
232
validate (mgr .lock );
219
- return subcategoryMap .valuesToArray ();
233
+ Collection <CategoryDB > categories = subcategoryMap .values ();
234
+ return categories .toArray (new Category [categories .size ()]);
220
235
}
221
236
222
237
/**
@@ -225,7 +240,8 @@ public Category[] getCategories() {
225
240
@ Override
226
241
public DataType [] getDataTypes () {
227
242
validate (mgr .lock );
228
- return dataTypeMap .valuesToArray ();
243
+ Collection <DataType > dataTypes = dataTypeMap .values ();
244
+ return dataTypes .toArray (new DataType [dataTypes .size ()]);
229
245
}
230
246
231
247
/**
@@ -587,19 +603,137 @@ private void catagoryRenamed(CategoryDB childCategory, String oldName) {
587
603
}
588
604
589
605
void dataTypeRenamed (DataType childDataType , String oldName ) {
590
- dataTypeMap . remove (oldName );
591
- dataTypeMap . put ( childDataType . getName (), childDataType );
606
+ dataTypeRemoved (oldName );
607
+ dataTypeAdded ( childDataType );
592
608
}
593
609
594
- void dataTypeAdded (DataType childDataType ) {
595
- dataTypeMap .put (childDataType .getName (), childDataType );
610
+ void dataTypeAdded (DataType dataType ) {
611
+ String dtName = dataType .getName ();
612
+ dataTypeMap .put (dtName , dataType );
613
+ if (isConflictName (dtName )) {
614
+ conflictMap .addDataType (dataType );
615
+ }
596
616
}
597
617
598
618
void dataTypeRemoved (String dataTypeName ) {
599
619
dataTypeMap .remove (dataTypeName );
620
+ if (isConflictName (dataTypeName )) {
621
+ conflictMap .removeDataTypeName (dataTypeName );
622
+ }
600
623
}
601
624
602
625
void categoryAdded (CategoryDB cat ) {
603
626
subcategoryMap .put (cat .getName (), cat );
604
627
}
628
+
629
+ @ Override
630
+ public List <DataType > getDataTypesByBaseName (String dataTypeName ) {
631
+ List <DataType > list = new ArrayList <>();
632
+ String baseName = getBaseName (dataTypeName );
633
+
634
+ DataType baseType = dataTypeMap .get (baseName );
635
+ if (baseType != null ) {
636
+ list .add (baseType );
637
+ }
638
+
639
+ List <DataType > relatedNameDataTypes = conflictMap .getDataTypesForBaseName (baseName );
640
+ list .addAll (relatedNameDataTypes );
641
+ return list ;
642
+ }
643
+
644
+ /**
645
+ * Class to handle complexities of having a map as the value in a LazyLoadingCachingMap
646
+ * This map uses data type's base name as the key (i.e. all .conflict suffixex stripped off.)
647
+ * The value is another map that maps the actual data type's name to the datatype. This map
648
+ * effectively provides an efficient way to get all data types in a category that have the
649
+ * same name, but possibly have had their name modified (by appending .conflict) to get around
650
+ * the requirement that names have to be unique in the same category.
651
+ */
652
+ class ConflictMap extends LazyLoadingCachingMap <String , Map <String , DataType >> {
653
+
654
+ ConflictMap (Lock lock ) {
655
+ super (lock );
656
+ }
657
+
658
+ /**
659
+ * Creates a map of all data types whose name has a .conflict suffix where the key
660
+ * is the base name and the value is a map of actual name to data type. This mapping is
661
+ * maintained as a lazy cache map.
662
+ * @return the loaded map
663
+ */
664
+ @ Override
665
+ protected Map <String , Map <String , DataType >> loadMap () {
666
+ Map <String , Map <String , DataType >> map = new HashMap <>();
667
+ Collection <DataType > values = dataTypeMap .values ();
668
+ for (DataType dataType : values ) {
669
+ String dataTypeName = dataType .getName ();
670
+ if (isConflictName (dataTypeName )) {
671
+ String baseName = getBaseName (dataTypeName );
672
+ Map <String , DataType > innerMap = map .get (baseName );
673
+ if (innerMap == null ) {
674
+ innerMap = new HashMap <>();
675
+ map .put (baseName , innerMap );
676
+ }
677
+ innerMap .put (dataTypeName , dataType );
678
+ }
679
+ }
680
+ return map ;
681
+ }
682
+
683
+ /**
684
+ * Adds the data type to the conflict mapping structure. If the mapping is currently not
685
+ * loaded then this method can safely do nothing.
686
+ * @param dataType the data type to add to the mapping if the mapping is already loaded
687
+ */
688
+ synchronized void addDataType (DataType dataType ) {
689
+ Map <String , Map <String , DataType >> map = getMap ();
690
+ if (map == null ) {
691
+ return ;
692
+ }
693
+
694
+ String dataTypeName = dataType .getName ();
695
+ String baseName = getBaseName (dataTypeName );
696
+ Map <String , DataType > innerMap = map .get (baseName );
697
+ if (innerMap == null ) {
698
+ innerMap = new HashMap <>();
699
+ put (baseName , innerMap );
700
+ }
701
+ innerMap .put (dataTypeName , dataType );
702
+ }
703
+
704
+ /**
705
+ * Removes the data type with the given name from the conflict mapping structure. If the
706
+ * mapping is currently not loaded then this method can safely do nothing.
707
+ * @param dataTypeName the name of the data type to remove from this mapping
708
+ */
709
+ synchronized void removeDataTypeName (String dataTypeName ) {
710
+ Map <String , Map <String , DataType >> map = getMap ();
711
+ if (map == null ) {
712
+ return ;
713
+ }
714
+ String baseName = getBaseName (dataTypeName );
715
+ Map <String , DataType > innerMap = map .get (baseName );
716
+ if (innerMap == null ) {
717
+ return ;
718
+ }
719
+ innerMap .remove (dataTypeName );
720
+ }
721
+
722
+ /**
723
+ * Returns a list of all data types that have conflict names for the given base name
724
+ * @param baseName the data type base name to search for (i.e. the .conflict suffix removed)
725
+ * @return a list of all conflict named data types that would have the given base name if
726
+ * no conflicts existed
727
+ */
728
+ List <DataType > getDataTypesForBaseName (String baseName ) {
729
+ Map <String , DataType > map = get (baseName );
730
+ if (map == null ) {
731
+ return Collections .emptyList ();
732
+ }
733
+ synchronized (this ) {
734
+ return new ArrayList <>(map .values ());
735
+ }
736
+ }
737
+
738
+ }
605
739
}
0 commit comments