diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java index de1fab842e..df00960644 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java @@ -1226,14 +1226,159 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { public void createShortenedTemplateNamesForClasses(List recoveredClasses) throws CancelledException { + // update recovered classes variable that stores shortened names such that all templated + // class names get generic classname<...> shortened name to start with + // also create a map of all same classname<> templates separated into unique parent namespaces + // and the list of recovered class objects in that namespace with the same generic + // classname<...> shortened name + Map>> templateClassesMap = + mapTemplateClasses(recoveredClasses); + + // now loop through them to make sure all in a particular namespace have unique shortened + // names or if unable to do that, remove the shortened name and use the full template name + Set shortenedNames = templateClassesMap.keySet(); + for (String shortenedName : shortenedNames) { + + monitor.checkCancelled(); + + Map> namespaceMap = + templateClassesMap.get(shortenedName); + for (Namespace parentNamespace : namespaceMap.keySet()) { + + monitor.checkCancelled(); + + // if only one, keep empty template + List sameNameClassesInNamespace = namespaceMap.get(parentNamespace); + if (sameNameClassesInNamespace.size() == 1) { + continue; + } + processDuplicateTemplates(sameNameClassesInNamespace, shortenedName, + parentNamespace); + } + } + + } + + /** + * Method to create unique shortened names for those blank templates that are dupes in a + * particular namespace + * @param sameNameClassesInNamespace the list of same name dupes in the given namespace + * @param shortenedName the duplicated shortened name + * @throws CancelledException if cancelled + */ + private void processDuplicateTemplates(List sameNameClassesInNamespace, + String shortenedName, Namespace parentNamespace) throws CancelledException { + + // first verify that all are in the same parent namespace + for (RecoveredClass recoveredClass : sameNameClassesInNamespace) { + if (!recoveredClass.getClassNamespace().getParentNamespace().equals(parentNamespace)) { + throw new IllegalArgumentException( + "This method is meant to dedupe shortened class names in the same parent namespace"); + } + } + + List classesToProcess = + new ArrayList(sameNameClassesInNamespace); + + // First, check for a simple internal to the template (ie just one item in it + // if that is the case then just keep the original name + for (RecoveredClass classWithSameShortName : sameNameClassesInNamespace) { + monitor.checkCancelled(); + + if (containsSimpleTemplate(classWithSameShortName.getName())) { + //reset shortened name variable to empty to indicate no shortened name + classWithSameShortName.addShortenedTemplatedName(new String()); + classesToProcess.remove(classWithSameShortName); + } + } + + // if none left after removing simple ones then continue processing next namespace + if (classesToProcess.isEmpty()) { + return; + } + + // if only one left after removing the simple templates then use it with first part of + // template internal (ie up to the first comma) + if (classesToProcess.size() == 1) { + RecoveredClass classWithSameShortName = classesToProcess.get(0); + String newName = getNewShortenedTemplateName(classWithSameShortName, 1); + classWithSameShortName.addShortenedTemplatedName(newName); + return; + } + + // if more than one complex left over after all the removals above, then keep trying to + // get unique name + int commaIndex = 1; + while (!classesToProcess.isEmpty()) { + + List leftoversWithSameShortName = + new ArrayList(classesToProcess); + + // update these classes so their short names include up to the n'th comma + for (RecoveredClass currentClass : leftoversWithSameShortName) { + monitor.checkCancelled(); + String newShortenedTemplateName = + getNewShortenedTemplateName(currentClass, commaIndex); + + // check to see if the new name is equal to the original class name + // if so, remove the shortened name and just use full name for that class + // also remove from list to process + if (newShortenedTemplateName.equals(currentClass.getName())) { + currentClass.addShortenedTemplatedName(new String()); + classesToProcess.remove(currentClass); + continue; + } + // else update with new shortened name + currentClass.addShortenedTemplatedName(newShortenedTemplateName); + } + + // if only one left then we are done + if (classesToProcess.size() == 1) { + classesToProcess.remove(0); + continue; + } + + // otherwise see if any are unique and if so remove from list + List classesWithUpdatedNames = + new ArrayList(classesToProcess); + + for (RecoveredClass currentClass : classesWithUpdatedNames) { + monitor.checkCancelled(); + + String shortenedTemplateName = currentClass.getShortenedTemplateName(); + + List classesWithSameShortName = getClassesWithSameShortenedName( + classesWithUpdatedNames, shortenedTemplateName); + + if (classesWithSameShortName.size() == 1) { + classesToProcess.remove(classesWithSameShortName.get(0)); + } + } + + // at this point either the classesToProcess will be empty and we are done + // OR there are still some with same (now with more of the template internal included) + // name so update commaIndex so that on next pass the internal will add more text up + // to this new comma index and so on until all are unique or back to their original + // full template name + commaIndex++; + } + + } + + private List getClassesWithTemplateNames(List recoveredClasses) + throws CancelledException { + List classesWithTemplates = new ArrayList(); // create list with only classes that have templates in name and add completely stripped // template name to class var - Iterator recoveredClassesIterator = recoveredClasses.iterator(); - while (recoveredClassesIterator.hasNext()) { + for (RecoveredClass recoveredClass : recoveredClasses) { monitor.checkCancelled(); - RecoveredClass recoveredClass = recoveredClassesIterator.next(); + + if (!recoveredClass.getShortenedTemplateName().isEmpty()) { + classesWithTemplates.add(recoveredClass); + continue; + } String className = recoveredClass.getName(); @@ -1243,115 +1388,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { classesWithTemplates.add(recoveredClass); } } - - // iterate over map and remove entries that already have unique shortened names on map and - // add those unique names to class as shorted name - // for those with non-unique names, process them as a group of matched names - List classesToProcess = new ArrayList(classesWithTemplates); - - Iterator classWithTemplatesIterator = classesWithTemplates.iterator(); - - while (classWithTemplatesIterator.hasNext()) { - monitor.checkCancelled(); - RecoveredClass currentClass = classWithTemplatesIterator.next(); - - // skip if already processed - if (!classesToProcess.contains(currentClass)) { - continue; - } - - String currentShortenedName = currentClass.getShortenedTemplateName(); - - // if removing the middle of template results in unique name then keep that name and - // remove class from list to process - List classesWithSameShortenedName = - getClassesWithSameShortenedName(classesToProcess, currentShortenedName); - - if (classesWithSameShortenedName.size() == 1) { - classesToProcess.remove(currentClass); - continue; - } - - Iterator classesWithSameShortnameIterator = - classesWithSameShortenedName.iterator(); - while (classesWithSameShortnameIterator.hasNext()) { - monitor.checkCancelled(); - - RecoveredClass classWithSameShortName = classesWithSameShortnameIterator.next(); - - // if removing the middle of template results in duplicate names then - // check for a simple internal to the template (ie just one item in it - // if that is the case then just keep the original name - if (containsSimpleTemplate(classWithSameShortName.getName())) { - classWithSameShortName.addShortenedTemplatedName(new String()); - classesWithSameShortnameIterator.remove(); - classesToProcess.remove(classWithSameShortName); - } - } - - // if none left after removing simple ones then continue processing next class - if (classesWithSameShortenedName.isEmpty()) { - continue; - } - - // if only one left after removing the simple templates then use it with first part of - // template internal - if (classesWithSameShortenedName.size() == 1) { - RecoveredClass classWithSameShortName = classesWithSameShortenedName.get(0); - String newName = getNewShortenedTemplateName(classWithSameShortName, 1); - classWithSameShortName.addShortenedTemplatedName(newName); - classesToProcess.remove(classWithSameShortName); - continue; - } - - // if more than one complex left over after all the removals above, then keep trying to - // get unique name - int commaIndex = 1; - while (!classesWithSameShortenedName.isEmpty()) { - - List leftoversWithSameShortName = - new ArrayList(classesWithSameShortenedName); - - // update all their shorted names to include up to the n'th comma - Iterator leftoversIterator = leftoversWithSameShortName.iterator(); - - while (leftoversIterator.hasNext()) { - - monitor.checkCancelled(); - RecoveredClass currentClassWithSameShortName = leftoversIterator.next(); - currentClassWithSameShortName.addShortenedTemplatedName( - getNewShortenedTemplateName(currentClassWithSameShortName, commaIndex)); - } - - // now iterate and see if any are unique and if so remove from list - // if not, add up to next comma and so on until all are unique - List leftovers2WithSameShortName = - new ArrayList(classesWithSameShortenedName); - Iterator leftovers2Iterator = - leftovers2WithSameShortName.iterator(); - - while (leftovers2Iterator.hasNext()) { - - monitor.checkCancelled(); - RecoveredClass currentClassWithSameShortName = leftovers2Iterator.next(); - - String shortenedTemplateName = - currentClassWithSameShortName.getShortenedTemplateName(); - - List classesWithSameShortName = - getClassesWithSameShortenedName(classesToProcess, shortenedTemplateName); - - if (classesWithSameShortName.size() == 1) { - classesToProcess.remove(classesWithSameShortName.get(0)); - classesWithSameShortenedName.remove(classesWithSameShortName.get(0)); - } - } - - commaIndex++; - } - - } - + return classesWithTemplates; } /** @@ -1372,7 +1409,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { return nameWithoutTemplates; } - public String getNewShortenedTemplateName(RecoveredClass recoveredClass, int commaIndex) { + private String getNewShortenedTemplateName(RecoveredClass recoveredClass, int commaIndex) { String className = recoveredClass.getName(); @@ -1393,21 +1430,62 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { return shortenedName; } - public List getClassesWithSameShortenedName( + private Map> mapClassesWithSameShortenedName( List templateClasses, String shortenedName) throws CancelledException { - List classesWithSameShortenedName = new ArrayList(); + Map> sameNamespaceMap = new HashMap<>(); - Iterator classIterator = templateClasses.iterator(); - while (classIterator.hasNext()) { + for (RecoveredClass currentClass : templateClasses) { monitor.checkCancelled(); - RecoveredClass currentClass = classIterator.next(); - if (currentClass.getShortenedTemplateName().equals(shortenedName)) { - classesWithSameShortenedName.add(currentClass); + Namespace parentNamespace = currentClass.getClassNamespace().getParentNamespace(); + List sameShortNameClasses = sameNamespaceMap.get(parentNamespace); + if (sameShortNameClasses == null) { + sameShortNameClasses = new ArrayList<>(); + } + sameShortNameClasses.add(currentClass); + sameNamespaceMap.put(parentNamespace, sameShortNameClasses); } } - return classesWithSameShortenedName; + return sameNamespaceMap; + + } + + private List getClassesWithSameShortenedName( + List templateClasses, String shortenedName) throws CancelledException { + + List sameShortNameClasses = new ArrayList<>(); + + for (RecoveredClass currentClass : templateClasses) { + monitor.checkCancelled(); + if (currentClass.getShortenedTemplateName().equals(shortenedName)) { + + sameShortNameClasses.add(currentClass); + + } + } + return sameShortNameClasses; + + } + + private Map>> mapTemplateClasses( + List recoveredClasses) throws CancelledException { + + List templateClasses = getClassesWithTemplateNames(recoveredClasses); + + Map>> sameNameMap = new HashMap<>(); + + for (RecoveredClass currentClass : templateClasses) { + monitor.checkCancelled(); + + String shortenedName = currentClass.getShortenedTemplateName(); + Map> sameShortNamesMap = sameNameMap.get(shortenedName); + if (sameShortNamesMap == null) { + sameNameMap.put(shortenedName, + mapClassesWithSameShortenedName(templateClasses, shortenedName)); + } + } + return sameNameMap; }