mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch
'origin/GP-1374-dragonmacher-sort-exported-enum-values--SQUASHED' (Closes #1664)
This commit is contained in:
commit
353a85e4fd
8 changed files with 225 additions and 108 deletions
|
@ -30,7 +30,6 @@ import ghidra.util.Msg;
|
|||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.xml.*;
|
||||
import ghidra.xml.*;
|
||||
|
||||
|
@ -245,7 +244,7 @@ public class DataTypesXmlMgr {
|
|||
private boolean processEnum(XmlTreeNode root) {
|
||||
XmlElement element = root.getStartElement();
|
||||
String name = element.getAttribute("NAME");
|
||||
String comment = getRegularComment(root);
|
||||
String enuumComment = getRegularComment(root);
|
||||
CategoryPath cp = getCategoryPath(element);
|
||||
int size = XmlUtilities.parseInt(element.getAttribute("SIZE"), defaultEnumSize);
|
||||
|
||||
|
@ -257,9 +256,10 @@ public class DataTypesXmlMgr {
|
|||
XmlElement childElement = node.getStartElement();
|
||||
String entryName = childElement.getAttribute("NAME");
|
||||
long entryValue = XmlUtilities.parseLong(childElement.getAttribute("VALUE"));
|
||||
enuum.add(entryName, entryValue);
|
||||
String comment = childElement.getAttribute("COMMENT");
|
||||
enuum.add(entryName, entryValue, comment);
|
||||
}
|
||||
enuum.setDescription(comment);
|
||||
enuum.setDescription(enuumComment);
|
||||
dataManager.addDataType(enuum, null);
|
||||
return true;
|
||||
}
|
||||
|
@ -288,6 +288,7 @@ public class DataTypesXmlMgr {
|
|||
td.setCategoryPath(cp);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
log.appendMsg("Unable to place typedef '" + name + "' in category '" + cp + "'");
|
||||
}
|
||||
|
||||
dataManager.addDataType(td, null);
|
||||
|
@ -546,11 +547,11 @@ public class DataTypesXmlMgr {
|
|||
writeRegularComment(writer, enuum.getDescription());
|
||||
|
||||
String[] names = enuum.getNames();
|
||||
Arrays.sort(names);
|
||||
for (String name : names) {
|
||||
attrs = new XmlAttributes();
|
||||
attrs.addAttribute("NAME", name);
|
||||
attrs.addAttribute("VALUE", enuum.getValue(name), true);
|
||||
attrs.addAttribute("COMMENT", enuum.getComment(name));
|
||||
writer.startElement("ENUM_ENTRY", attrs);
|
||||
writer.endElement("ENUM_ENTRY");
|
||||
}
|
||||
|
@ -666,8 +667,8 @@ public class DataTypesXmlMgr {
|
|||
|
||||
/**
|
||||
* Output data types in XML format for debugging purposes.
|
||||
* NOTE: There is no support for reading the XML produced by this
|
||||
* method.
|
||||
* NOTE: There is no support for reading the XML produced by this method.
|
||||
* @param dataManager the data type manager
|
||||
* @param outputFilename name of the output file
|
||||
* @throws IOException if there was a problem writing to the file
|
||||
*/
|
||||
|
@ -683,9 +684,10 @@ public class DataTypesXmlMgr {
|
|||
MessageLog log = new MessageLog();
|
||||
DataTypesXmlMgr mgr = new DataTypesXmlMgr(dataManager, log);
|
||||
try {
|
||||
mgr.write(writer, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
mgr.write(writer, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// can't happen with dummy monitor
|
||||
}
|
||||
|
||||
writer.close();
|
||||
|
|
|
@ -29,7 +29,7 @@ import ghidra.program.model.data.Enum;
|
|||
import ghidra.program.model.data.EnumDataType;
|
||||
import ghidra.program.util.ChangeManager;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Tests for Enum data types.
|
||||
|
@ -40,10 +40,6 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private DataTypeManagerDB dataMgr;
|
||||
private int transactionID;
|
||||
|
||||
public EnumTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
program = createDefaultProgram("Test", ProgramBuilder._TOY, this);
|
||||
|
@ -223,7 +219,7 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Enum enummDT = (Enum) dataMgr.resolve(enumm, null);
|
||||
assertNotNull(enummDT);
|
||||
|
||||
c.remove(enummDT, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
c.remove(enummDT, TaskMonitor.DUMMY);
|
||||
assertNull(c.getDataType("Color"));
|
||||
|
||||
assertTrue(enummDT.isDeleted());
|
||||
|
@ -294,6 +290,7 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Assert.fail("Should have gotten no such element exception!");
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,27 +332,56 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
myEnum.add("Green", 15);
|
||||
myEnum.add("Blue", 20);
|
||||
assertTrue(enummDT.isEquivalent(myEnum));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameSort() {
|
||||
|
||||
Enum myEnum = new EnumDataType("Color", 1);
|
||||
myEnum.add("Red", 1);
|
||||
myEnum.add("Green", 5);
|
||||
myEnum.add("Blue", 10);
|
||||
|
||||
String[] names = myEnum.getNames();
|
||||
assertEquals("Red", names[0]);
|
||||
assertEquals("Green", names[1]);
|
||||
assertEquals("Blue", names[2]);
|
||||
|
||||
myEnum = new EnumDataType("Color", 1);
|
||||
myEnum.add("Red", 20);
|
||||
myEnum.add("Green", 1);
|
||||
myEnum.add("Blue", 3);
|
||||
|
||||
names = myEnum.getNames();
|
||||
assertEquals("Green", names[0]);
|
||||
assertEquals("Blue", names[1]);
|
||||
assertEquals("Red", names[2]);
|
||||
|
||||
// multiple names per value, requires sub-sorting
|
||||
myEnum = new EnumDataType("Color", 1);
|
||||
myEnum.add("Red", 20);
|
||||
myEnum.add("Pink", 20);
|
||||
myEnum.add("Salmon", 20);
|
||||
myEnum.add("Green", 1);
|
||||
myEnum.add("AnotherGreen", 1);
|
||||
myEnum.add("Blue", 3);
|
||||
|
||||
names = myEnum.getNames();
|
||||
assertEquals("AnotherGreen", names[0]);
|
||||
assertEquals("Green", names[1]);
|
||||
assertEquals("Blue", names[2]);
|
||||
assertEquals("Pink", names[3]);
|
||||
assertEquals("Red", names[4]);
|
||||
assertEquals("Salmon", names[5]);
|
||||
}
|
||||
|
||||
private void waitForListenerCount(DomainObjListener listener, int count) {
|
||||
int cnt = 0;
|
||||
try {
|
||||
while (cnt++ < 10 && listener.getCount() != count) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
Thread.sleep(300);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
waitForCondition(() -> listener.getCount() == count);
|
||||
}
|
||||
|
||||
private class DomainObjListener implements DomainObjectListener {
|
||||
private int count;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.model.DomainObjectListener#domainObjectChanged(ghidra.framework.model.DomainObjectChangedEvent)
|
||||
*/
|
||||
@Override
|
||||
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||
for (int i = 0; i < ev.numRecords(); i++) {
|
||||
|
|
|
@ -45,7 +45,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
private EnumValueDBAdapter valueAdapter;
|
||||
|
||||
private Map<String, Long> nameMap; // name to value
|
||||
private Map<Long, List<String>> valueMap; // value to names
|
||||
private TreeMap<Long, List<String>> valueMap; // value to names
|
||||
private Map<String, String> commentMap; // name to comment
|
||||
private List<BitGroup> bitGroups;
|
||||
|
||||
|
@ -86,7 +86,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
private void initialize() throws IOException {
|
||||
bitGroups = null;
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
valueMap = new TreeMap<>();
|
||||
commentMap = new HashMap<>();
|
||||
|
||||
Field[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
|
@ -190,9 +190,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
try {
|
||||
checkIsValid();
|
||||
initializeIfNeeded();
|
||||
long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray();
|
||||
Arrays.sort(values);
|
||||
return values;
|
||||
return valueMap.keySet().stream().mapToLong(Long::longValue).toArray();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -205,9 +203,15 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
try {
|
||||
checkIsValid();
|
||||
initializeIfNeeded();
|
||||
String[] names = nameMap.keySet().toArray(new String[nameMap.size()]);
|
||||
Arrays.sort(names);
|
||||
return names;
|
||||
|
||||
// names are first sorted by int value, then sub-sorted by name value
|
||||
List<String> names = new ArrayList<>();
|
||||
Collection<List<String>> values = valueMap.values();
|
||||
for (List<String> list : values) {
|
||||
Collections.sort(list);
|
||||
names.addAll(list);
|
||||
}
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -319,7 +323,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
|
||||
bitGroups = null;
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
valueMap = new TreeMap<>();
|
||||
commentMap = new HashMap<>();
|
||||
|
||||
Field[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
|
|
|
@ -19,10 +19,11 @@ import java.io.IOException;
|
|||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
/**
|
||||
* A class used to convert data types into ANSI-C.
|
||||
|
@ -53,25 +54,23 @@ public class DataTypeWriter {
|
|||
private boolean cppStyleComments = false;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class using the
|
||||
* given writer. The default annotation handler is used.
|
||||
* @param dtm data-type manager corresponding to target program or null
|
||||
* for default
|
||||
* Constructs a new instance of this class using the given writer. The default annotation
|
||||
* handler is used.
|
||||
* @param dtm data-type manager corresponding to target program or null for default
|
||||
* @param writer the writer to use when writing data types
|
||||
* @throws IOException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
public DataTypeWriter(DataTypeManager dtm, Writer writer) throws IOException {
|
||||
this(dtm, writer, new DefaultAnnotationHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class using the
|
||||
* given writer. The default annotation handler is used.
|
||||
* @param dtm data-type manager corresponding to target program or null
|
||||
* for default
|
||||
* Constructs a new instance of this class using the given writer. The default annotation
|
||||
* handler is used.
|
||||
* @param dtm data-type manager corresponding to target program or null for default
|
||||
* @param writer the writer to use when writing data types
|
||||
* @param cppStyleComments whether to use C++ style comments
|
||||
* @throws IOException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
public DataTypeWriter(DataTypeManager dtm, Writer writer, boolean cppStyleComments)
|
||||
throws IOException {
|
||||
|
@ -79,13 +78,11 @@ public class DataTypeWriter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class using the
|
||||
* given writer and annotation handler
|
||||
* @param dtm data-type manager corresponding to target program or null
|
||||
* for default
|
||||
* Constructs a new instance of this class using the given writer and annotation handler
|
||||
* @param dtm data-type manager corresponding to target program or null for default
|
||||
* @param writer the writer to use when writing data types
|
||||
* @param annotator the annotation handler to use to annotate the data types
|
||||
* @throws IOException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator)
|
||||
throws IOException {
|
||||
|
@ -93,14 +90,12 @@ public class DataTypeWriter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class using the
|
||||
* given writer and annotation handler
|
||||
* @param dtm data-type manager corresponding to target program or null
|
||||
* for default
|
||||
* Constructs a new instance of this class using the given writer and annotation handler
|
||||
* @param dtm data-type manager corresponding to target program or null for default
|
||||
* @param writer the writer to use when writing data types
|
||||
* @param annotator the annotation handler to use to annotate the data types
|
||||
* @param cppStyleComments whether to use C++ style comments
|
||||
* @throws IOException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator,
|
||||
boolean cppStyleComments) throws IOException {
|
||||
|
@ -133,8 +128,8 @@ public class DataTypeWriter {
|
|||
* Converts all data types in the data type manager into ANSI-C code.
|
||||
* @param dataTypeManager the manager containing the data types to write
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if an I/O error occurs when writing the data types to the specified writer
|
||||
* @throws CancelledException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
public void write(DataTypeManager dataTypeManager, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -145,8 +140,8 @@ public class DataTypeWriter {
|
|||
* Converts all data types in the category into ANSI-C code.
|
||||
* @param category the category containing the datatypes to write
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if an I/O error occurs when writing the data types to the specified writer
|
||||
* @throws CancelledException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
public void write(Category category, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -166,8 +161,8 @@ public class DataTypeWriter {
|
|||
* Converts all data types in the array into ANSI-C code.
|
||||
* @param dataTypes the data types to write
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if an I/O error occurs when writing the data types to the specified writer
|
||||
* @throws CancelledException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
public void write(DataType[] dataTypes, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -184,8 +179,8 @@ public class DataTypeWriter {
|
|||
* Converts all data types in the list into ANSI-C code.
|
||||
* @param dataTypes the data types to write
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if an I/O error occurs when writing the data types to the specified writer
|
||||
* @throws CancelledException
|
||||
* @throws IOException if there is an exception writing the output
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
public void write(List<DataType> dataTypes, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -222,8 +217,8 @@ public class DataTypeWriter {
|
|||
/**
|
||||
* Writes the data type as ANSI-C using the underlying writer.
|
||||
* @param dt the data type to write as ANSI-C
|
||||
* @param monitor
|
||||
* @throws IOException
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
private void doWrite(DataType dt, TaskMonitor monitor, boolean throwExceptionOnInvalidType)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -456,7 +451,7 @@ public class DataTypeWriter {
|
|||
|
||||
String compositeType = composite instanceof Structure ? "struct" : "union";
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(compositeType + " " + composite.getDisplayName() + " {");
|
||||
|
||||
String descrip = composite.getDescription();
|
||||
|
@ -478,7 +473,7 @@ public class DataTypeWriter {
|
|||
writer.write(EOL);
|
||||
}
|
||||
|
||||
private void writeComponent(DataTypeComponent component, Composite composite, StringBuffer sb,
|
||||
private void writeComponent(DataTypeComponent component, Composite composite, StringBuilder sb,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
sb.append(" ");
|
||||
sb.append(annotator.getPrefix(composite, component));
|
||||
|
@ -504,14 +499,13 @@ public class DataTypeWriter {
|
|||
}
|
||||
|
||||
private String getTypeDeclaration(String name, DataType dataType, int instanceLength,
|
||||
boolean writeEnabled, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
boolean writeEnabled, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String componentString = null;
|
||||
if (dataType instanceof Dynamic) {
|
||||
componentString = getDynamicComponentString((Dynamic) dataType, name, instanceLength);
|
||||
|
@ -581,11 +575,12 @@ public class DataTypeWriter {
|
|||
}
|
||||
|
||||
writer.write("typedef enum " + enumName + " " + "{");
|
||||
String descrip = enumm.getDescription();
|
||||
if (descrip != null && descrip.length() != 0) {
|
||||
writer.write(" " + comment(descrip));
|
||||
String description = enumm.getDescription();
|
||||
if (description != null && description.length() != 0) {
|
||||
writer.write(" " + comment(description));
|
||||
}
|
||||
writer.write(EOL);
|
||||
|
||||
String[] names = enumm.getNames();
|
||||
for (int j = 0; j < names.length; j++) {
|
||||
writer.write(" ");
|
||||
|
@ -593,7 +588,14 @@ public class DataTypeWriter {
|
|||
writer.write(names[j]);
|
||||
writer.write("=");
|
||||
writer.write(Long.toString(enumm.getValue(names[j])));
|
||||
|
||||
String comment = enumm.getComment(names[j]);
|
||||
if (!StringUtils.isBlank(comment)) {
|
||||
writer.write(" " + comment(comment));
|
||||
}
|
||||
|
||||
writer.write(annotator.getSuffix(enumm, names[j]));
|
||||
|
||||
if (j < names.length - 1) {
|
||||
writer.write(",");
|
||||
}
|
||||
|
@ -606,7 +608,7 @@ public class DataTypeWriter {
|
|||
|
||||
/**
|
||||
* Typedef Format: typedef <TYPE_DEF_NAME> <BASE_TYPE_NAME>
|
||||
* @throws CancelledException
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
private void writeTypeDef(TypeDef typeDef, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -704,16 +706,14 @@ public class DataTypeWriter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Write all built-in data types declarations into ANSI-C code.
|
||||
* Those types whose name matches the corresponding primitive C-type.
|
||||
* are not included.
|
||||
* @throws IOException if an I/O error occurs when writing the data types to the specified writer
|
||||
* @throws CancelledException
|
||||
* Write all built-in data types declarations into ANSI-C code. Those types whose name matches
|
||||
* the corresponding primitive C-type. are not included.
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
private void writeBuiltInDeclarations(DataTypeManager manager) throws IOException {
|
||||
|
||||
try {
|
||||
write(DataType.DEFAULT, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
write(DataType.DEFAULT, TaskMonitor.DUMMY);
|
||||
|
||||
SourceArchive builtInArchive =
|
||||
manager.getSourceArchive(DataTypeManager.BUILT_IN_ARCHIVE_UNIVERSAL_ID);
|
||||
|
@ -726,7 +726,7 @@ public class DataTypeWriter {
|
|||
(dt instanceof Dynamic)) {
|
||||
continue;
|
||||
}
|
||||
write(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
write(dt, TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
|
@ -872,7 +872,7 @@ public class DataTypeWriter {
|
|||
buf.append(ghidra.program.model.listing.FunctionSignature.VAR_ARGS_DISPLAY_STRING);
|
||||
}
|
||||
if ((n == 0) && (!hasVarArgs)) { // If no parameters
|
||||
buf.append(DataType.VOID.getName()); // Print "void" keyword
|
||||
buf.append(VoidDataType.dataType.getName()); // Print "void" keyword
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
|
|
|
@ -52,8 +52,8 @@ public interface Enum extends DataType {
|
|||
public long[] getValues();
|
||||
|
||||
/**
|
||||
* Get the names of the enum entries. The returned names are sorted using String's natural
|
||||
* sort order.
|
||||
* Get the names of the enum entries. The returned names are first sorted by the enum int
|
||||
* value, then sub-sorted by name value where there are multiple name values per int value.
|
||||
* @return the names of the enum entries.
|
||||
*/
|
||||
public String[] getNames();
|
||||
|
|
|
@ -34,7 +34,7 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
||||
|
||||
private Map<String, Long> nameMap; // name to value
|
||||
private Map<Long, List<String>> valueMap; // value to names
|
||||
private TreeMap<Long, List<String>> valueMap; // value to names
|
||||
private Map<String, String> commentMap; // name to comment
|
||||
private int length;
|
||||
private String description;
|
||||
|
@ -54,7 +54,7 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
throw new IllegalArgumentException("unsupported enum length: " + length);
|
||||
}
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
valueMap = new TreeMap<>();
|
||||
commentMap = new HashMap<>();
|
||||
this.length = length;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
throw new IllegalArgumentException("unsupported enum length: " + length);
|
||||
}
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
valueMap = new TreeMap<>();
|
||||
commentMap = new HashMap<>();
|
||||
this.length = length;
|
||||
}
|
||||
|
@ -108,15 +108,19 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
@Override
|
||||
public long[] getValues() {
|
||||
long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray();
|
||||
Arrays.sort(values);
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getNames() {
|
||||
String[] names = nameMap.keySet().toArray(new String[nameMap.size()]);
|
||||
Arrays.sort(names);
|
||||
return names;
|
||||
// names are first sorted by int value, then sub-sorted by name value
|
||||
List<String> names = new ArrayList<>();
|
||||
Collection<List<String>> values = valueMap.values();
|
||||
for (List<String> list : values) {
|
||||
Collections.sort(list);
|
||||
names.addAll(list);
|
||||
}
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -417,7 +421,7 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
}
|
||||
Enum enumm = (Enum) dataType;
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
valueMap = new TreeMap<>();
|
||||
commentMap = new HashMap<>();
|
||||
setLength(enumm.getLength());
|
||||
String[] names = enumm.getNames();
|
||||
|
|
|
@ -33,10 +33,6 @@ public class DataTypeWriterTest extends AbstractGTest {
|
|||
private StringWriter writer;
|
||||
private DataTypeWriter dtWriter;
|
||||
|
||||
public DataTypeWriterTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
|
@ -105,8 +101,16 @@ public class DataTypeWriterTest extends AbstractGTest {
|
|||
enumm.add("E", 4);
|
||||
dtWriter.write(enumm, TaskMonitor.DUMMY);
|
||||
String actual = writer.getBuffer().toString();
|
||||
String expected = "typedef enum myEnum {" + EOL + " A=0," + EOL + " B=1," + EOL +
|
||||
" C=2," + EOL + " D=3," + EOL + " E=4" + EOL + "} myEnum;" + EOL + EOL;
|
||||
|
||||
//@formatter:off
|
||||
String expected = "typedef enum myEnum {" + EOL +
|
||||
" A=0," + EOL +
|
||||
" B=1," + EOL +
|
||||
" C=2," + EOL +
|
||||
" D=3," + EOL +
|
||||
" E=4" + EOL +
|
||||
"} myEnum;" + EOL + EOL;
|
||||
//@formatter:on
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
@ -120,8 +124,84 @@ public class DataTypeWriterTest extends AbstractGTest {
|
|||
enumm.add("E", 254);
|
||||
dtWriter.write(enumm, TaskMonitor.DUMMY);
|
||||
String actual = writer.getBuffer().toString();
|
||||
String expected = "typedef enum myEnum {" + EOL + " A=4," + EOL + " B=8," + EOL +
|
||||
" C=16," + EOL + " D=32," + EOL + " E=254" + EOL + "} myEnum;" + EOL + EOL;
|
||||
|
||||
//@formatter:off
|
||||
String expected = "typedef enum myEnum {" + EOL +
|
||||
" A=4," + EOL +
|
||||
" B=8," + EOL +
|
||||
" C=16," + EOL +
|
||||
" D=32," + EOL +
|
||||
" E=254" + EOL +
|
||||
"} myEnum;" + EOL + EOL;
|
||||
//@formatter:on
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnum_WithComments() throws IOException, CancelledException {
|
||||
Enum enumm = new EnumDataType("myEnum", 1);
|
||||
enumm.add("A", 0);
|
||||
enumm.add("B", 1, "B Comment");
|
||||
enumm.add("C", 2);
|
||||
enumm.add("D", 3, "D Comment");
|
||||
enumm.add("E", 4);
|
||||
dtWriter.write(enumm, TaskMonitor.DUMMY);
|
||||
String actual = writer.getBuffer().toString();
|
||||
|
||||
//@formatter:off
|
||||
String expected = "typedef enum myEnum {" + EOL +
|
||||
" A=0," + EOL +
|
||||
" B=1 /* B Comment */," + EOL +
|
||||
" C=2," + EOL +
|
||||
" D=3 /* D Comment */," + EOL +
|
||||
" E=4" + EOL +
|
||||
"} myEnum;" + EOL + EOL;
|
||||
//@formatter:on
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnum_MultipleNamesPerValue() throws IOException, CancelledException {
|
||||
Enum enumm = new EnumDataType("myEnum", 1);
|
||||
enumm.add("A", 4);
|
||||
enumm.add("Two", 8);
|
||||
enumm.add("One", 8);
|
||||
enumm.add("End", 32);
|
||||
dtWriter.write(enumm, TaskMonitor.DUMMY);
|
||||
String actual = writer.getBuffer().toString();
|
||||
|
||||
//@formatter:off
|
||||
String expected = "typedef enum myEnum {" + EOL +
|
||||
" A=4," + EOL +
|
||||
" One=8," + EOL +
|
||||
" Two=8," + EOL +
|
||||
" End=32" + EOL +
|
||||
"} myEnum;" + EOL + EOL;
|
||||
//@formatter:on
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnum_NamesOrderDifferenentThanValueOrder()
|
||||
throws IOException, CancelledException {
|
||||
Enum enumm = new EnumDataType("myEnum", 1);
|
||||
enumm.add("E", 4);
|
||||
enumm.add("C", 8);
|
||||
enumm.add("D", 16);
|
||||
enumm.add("B", 32);
|
||||
enumm.add("A", 254);
|
||||
dtWriter.write(enumm, TaskMonitor.DUMMY);
|
||||
String actual = writer.getBuffer().toString();
|
||||
|
||||
//@formatter:off
|
||||
String expected = "typedef enum myEnum {" + EOL +
|
||||
" E=4," + EOL +
|
||||
" C=8," + EOL +
|
||||
" D=16," + EOL +
|
||||
" B=32," + EOL +
|
||||
" A=254" + EOL +
|
||||
"} myEnum;" + EOL + EOL;
|
||||
//@formatter:on
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.NoSuchElementException;
|
|||
import org.junit.*;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Tests for Enum data types.
|
||||
|
@ -166,7 +166,7 @@ public class EnumTest extends AbstractGTest {
|
|||
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
assertNotNull(enummDT);
|
||||
|
||||
c.remove(enummDT, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
c.remove(enummDT, TaskMonitor.DUMMY);
|
||||
assertNull(c.getDataType("Color"));
|
||||
|
||||
assertTrue(enummDT.isDeleted());
|
||||
|
@ -235,6 +235,7 @@ public class EnumTest extends AbstractGTest {
|
|||
Assert.fail("Should have gotten no such element exception!");
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue