GP-1316 - Enums - Updates for PR to add comments to enum values

This commit is contained in:
dragonmacher 2021-09-30 14:44:52 -04:00
parent 7398d26e84
commit e80dedcbdf
25 changed files with 715 additions and 1219 deletions

View file

@ -25,17 +25,24 @@
<ul> <ul>
<li>The <i>Name</i> column in the table is the name of the enum entry.</li> <li>The <i>Name</i> column in the table is the name of the enum entry.</li>
<li>The <i>Value</i> column in the table is the value of the enum entry.</li> <li>The <i>Value</i> column in the table is the value of the enum entry.</li>
<li>The <i>Comment</i> column in the table is the comment for the enum entry.</li>
<li>The <i>Name</i> field below the table shows the name of the enum. <li>The <i>Name</i> field below the table shows the name of the enum.
Edit this field to change the name. Edit this field to change the name.
</li> </li>
<li>The <i>Description</i> field shows a short description for the enum; <li>The <i>Description</i> field shows a short description for the enum;
edit this field to update the description. edit this field to update the description.
</li> </li>
<li>The <i>Category</i> field shows where the enum resides which corresponds to the folder you were selecting when creating the enum; <li>The <i>Category</i> field shows where the enum resides which corresponds to the folder
the field is not editable, however, you can move it using the Data Type Manager after you have created it if you want to move it. you were selecting when creating the enum;
the field is not editable, however, you can move it using the Data Type Manager after
you have created it if you want to move it.
</li> </li>
<li>The <i>Size</i> field shows the number of bytes required when you apply <li>The <i>Size</i> field shows the number of bytes required when you apply
the enum. To edit this field, use the dropdown menu to choose a new size. Note: If you are applying an enum to a data definition and do not see expected results in the decompiler it is probably because the size is incorrect. the enum. To edit this field, use the drop-down menu to choose a new size. Note: If you
are applying an enum to a data definition and do not see expected results in the
decompiler it is probably because the size is incorrect.
</li> </li>
</ul> </ul>
<p>When you make any change to the enum, the <p>When you make any change to the enum, the

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

View file

@ -246,6 +246,30 @@ class DataTypePanel extends JPanel {
insertLength(comp); insertLength(comp);
} }
private class EnumEntry implements Comparable<EnumEntry> {
private final String name;
private final long value;
private final String comment;
EnumEntry(String name, long value, String comment) {
this.name = name;
this.value = value;
this.comment = comment;
}
@Override
public int compareTo(EnumEntry o) {
int c = Long.compare(value, o.value);
if (c == 0) {
c = name.compareTo(o.name);
}
return c;
}
}
private void formatEnumText(Enum enuum) { private void formatEnumText(Enum enuum) {
formatSourceArchive(enuum); formatSourceArchive(enuum);
formatPath(enuum); formatPath(enuum);
@ -254,28 +278,41 @@ class DataTypePanel extends JPanel {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
String[] names = enuum.getNames(); int maxNameLength = 0;
int maxLength = 0; int maxValueLength = 0;
for (String name : names) {
if (name.length() > maxLength) {
maxLength = name.length();
}
}
long[] values = enuum.getValues();
Arrays.sort(values);
for (int i = 0; i < values.length; i++) { String[] names = enuum.getNames();
String name = enuum.getName(values[i]); EnumEntry[] entries = new EnumEntry[names.length];
name = pad(name, maxLength); for (int i = 0; i < names.length; i++) {
sb.append(" " + name + " = 0x" + Long.toHexString(values[i]) + " "); String name = names[i];
if (i < values.length - 1) { EnumEntry entry = new EnumEntry(name, enuum.getValue(name), enuum.getComment(name));
sb.append("\n"); entries[i] = entry;
} maxNameLength = Math.max(maxNameLength, name.length());
String valStr = Long.toHexString(entry.value);
maxValueLength = Math.max(maxValueLength, valStr.length());
} }
sb.append("\n }\n"); Arrays.sort(entries);
for (EnumEntry entry : entries) {
renderEnumEntry(entry, maxNameLength, maxValueLength);
}
sb.append("}\n");
insertString(sb.toString(), contentAttrSet); insertString(sb.toString(), contentAttrSet);
} }
private void renderEnumEntry(EnumEntry entry, int maxNameLength, int maxValueLength) {
String name = entry.name;
name = pad(name, maxNameLength);
String valStr = Long.toHexString(entry.value);
valStr = pad(valStr, maxValueLength);
insertString(" " + name, fieldNameAttrSet);
insertString(" = 0x" + valStr, contentAttrSet);
if (entry.comment != null) {
insertString(" " + entry.comment, commentAttrSet);
}
insertString("\n", contentAttrSet);
}
private void formatTypeDefText(TypeDef td) { private void formatTypeDefText(TypeDef td) {
formatSourceArchive(td); formatSourceArchive(td);
formatPath(td); formatPath(td);

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +15,8 @@
*/ */
package ghidra.app.plugin.core.datamgr.editor; package ghidra.app.plugin.core.datamgr.editor;
import generic.json.Json;
public class EnumEntry { public class EnumEntry {
private String name; private String name;
private long value; private long value;
@ -50,4 +51,9 @@ public class EnumEntry {
public void setComment(String newComment) { public void setComment(String newComment) {
this.comment = newComment; this.comment = newComment;
} }
@Override
public String toString() {
return Json.toString(this);
}
} }

View file

@ -266,8 +266,8 @@ class EnumTableModel extends AbstractSortedTableModel<EnumEntry> {
} }
private long findNextValue(int afterRow) { private long findNextValue(int afterRow) {
if (enumEntryList.size() == 0) { if (enumEntryList.isEmpty()) {
return new Long(0); return 0;
} }
if (afterRow < 0 || afterRow >= enumEntryList.size()) { if (afterRow < 0 || afterRow >= enumEntryList.size()) {
afterRow = 0; afterRow = 0;

View file

@ -1,698 +0,0 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on Aug 3, 2005
*/
package ghidra.app.plugin.prototype.dataArchiveUtilities;
import java.awt.Component;
import java.io.*;
import java.util.*;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.tool.ToolConstants;
import docking.widgets.filechooser.GhidraFileChooser;
import ghidra.MiscellaneousPluginPackage;
import ghidra.app.context.ListingActionContext;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.util.xml.DataTypesXmlMgr;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.*;
import ghidra.framework.preferences.Preferences;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.filechooser.ExtensionFileFilter;
import ghidra.util.task.*;
//@formatter:off
@PluginInfo(
status = PluginStatus.STABLE,
packageName = MiscellaneousPluginPackage.NAME,
category = PluginCategoryNames.CODE_VIEWER,
shortDescription = "Convert data archives",
description = "This plugin allows the user to convert GSL-generated archives back and forth to Ghidra data archives."
)
//@formatter:on
public class ArchiveConverterPlugin extends ProgramPlugin {
private static final String IMPORT_EXPORT_GROUP = "Import/Export";
final static String CONVERT_DATA = "Convert GSL- to data-archive";
final static String GSL_ARCHIVE_DIR = "GSL Archive Directory";
final static String GDT_ARCHIVE_DIR = "GDT Archive Directory";
final static String ALIGNMENT_TAG = "added for alignment";
final static String WRITE_GSL = "Write data-archive in GSL Format";
private GhidraFileChooser fileChooser;
private TypedefDataType dataUI;
private Hashtable<String, DataType> dataTypes = new Hashtable<>();
/**
* @param id
* @param plugintool
* @param consumeLocationChange
* @param consumeSelectionChange
*/
public ArchiveConverterPlugin(PluginTool plugintool) {
super(plugintool, false, false);
createActions();
}
public Program getProgram() {
return currentProgram;
}
@Override
public void dispose() {
super.dispose();
}
/**
*
*/
private void createActions() {
DockingAction parseAction = new DockingAction(CONVERT_DATA, getName()) {
@Override
public void actionPerformed(ActionContext context) {
File gslArchive =
chooseFile(tool.getToolFrame(), "Select GSL archive", GSL_ARCHIVE_DIR, "gsl");
new TaskLauncher(new GSLParserTask(tool, gslArchive), tool.getToolFrame());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return context.getContextObject() instanceof ListingActionContext;
}
};
String[] menuPath = { ToolConstants.MENU_FILE, "Parse GSL Archive..." };
parseAction.setMenuBarData(new MenuData(menuPath, IMPORT_EXPORT_GROUP));
parseAction.setEnabled(true);
tool.addAction(parseAction);
DockingAction writeGslAction = new DockingAction(WRITE_GSL, getName()) {
@Override
public void actionPerformed(ActionContext context) {
File gslInfile = chooseFile(tool.getToolFrame(), "Select input file",
GDT_ARCHIVE_DIR, FileDataTypeManager.SUFFIX);
File gslOutfile =
chooseFile(tool.getToolFrame(), "Select output file", GSL_ARCHIVE_DIR, "gsl");
new TaskLauncher(new GSLWriterTask(tool, gslInfile, gslOutfile),
tool.getToolFrame());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return context.getContextObject() instanceof ListingActionContext;
}
};
String[] menuPath2 = { ToolConstants.MENU_FILE, "Write GSL Archive..." };
writeGslAction.setMenuBarData(new MenuData(menuPath2, IMPORT_EXPORT_GROUP));
writeGslAction.setEnabled(true);
tool.addAction(writeGslAction);
}
private class GSLParserTask extends Task {
PluginTool myTool;
File gslArchive;
public GSLParserTask(PluginTool tool, File gslArchive) {
super("GSL Archive Parser", true, true, false);
this.gslArchive = gslArchive;
this.myTool = tool;
}
@Override
public void run(TaskMonitor monitor) {
int lineCount = 0;
try {
if (gslArchive != null) {
String gslName = gslArchive.getName();
String gslNameWithPath = gslArchive.getAbsolutePath();
monitor.setMessage("Parsing " + gslName);
FileDataTypeManager dtMgr = FileDataTypeManager.createFileArchive(
new File(gslNameWithPath + FileDataTypeManager.SUFFIX));
int id = dtMgr.startTransaction("process archive");
try {
addPrimitives(dtMgr);
BufferedReader reader = new BufferedReader(new FileReader(gslArchive));
while (reader.readLine() != null) {
lineCount++;
}
reader.close();
monitor.initialize(lineCount);
reader = new BufferedReader(new FileReader(gslArchive));
String line;
lineCount = 0;
DataType dt = null;
while (((line = reader.readLine()) != null) && !monitor.isCancelled()) {
try {
dt = parseLine(dtMgr, line);
if (dt != null) {
addDataType(dtMgr, dataTypes, dt);
}
if (lineCount % 100 == 0) {
monitor.setProgress(lineCount);
}
lineCount++;
}
catch (Exception e) {
Msg.error(this,
"Error in " + name + " at line " + lineCount + " of " +
gslArchive.getName() +
"...possibly an attempt to redefine a Ghidra primitive",
e);
}
}
reader.close();
}
finally {
dtMgr.endTransaction(id, true);
}
monitor.setMessage("Checking for parser errors");
searchForErrors(dtMgr);
monitor.setMessage("Writing XML file");
try {
DataTypesXmlMgr.writeAsXMLForDebug(dtMgr, gslNameWithPath);
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
try {
dtMgr.save();
}
catch (Exception e) {
Msg.showError(this, myTool.getToolFrame(), "GSL Archive Parser",
gslNameWithPath + ".gdt already exists - not overwritten", e);
}
dtMgr.close();
}
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
return;
}
}
private class GSLWriterTask extends Task {
File gslInfile;
File gslOutfile;
public GSLWriterTask(PluginTool tool, File gslInfile, File gslOutfile) {
super("GSL Archive Writer", true, false, false);
this.gslInfile = gslInfile;
this.gslOutfile = gslOutfile;
}
@Override
public void run(TaskMonitor monitor) {
if (gslInfile != null) {
DataTypeManager dtMgr = null;
try {
dtMgr = FileDataTypeManager.openFileArchive(gslInfile, false);
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
if (dtMgr != null) {
try {
monitor.setMessage("Writing " + gslOutfile.getName());
writeAsGsl(gslOutfile, dtMgr, monitor);
}
finally {
dtMgr.close();
}
}
}
return;
}
}
private DataType parseLine(FileDataTypeManager dtMgr, String line) {
DataType dt = null;
int index;
// "$$" doesn't get parsed correctly, so replace it with "$ $"
while ((index = line.indexOf("$$")) >= 0) {
line = line.substring(0, index + 1) + "noname" + line.substring(index + 1);
}
while ((index = line.indexOf("//")) >= 0) {
line = line.substring(0, index) + line.substring(index + 1);
}
StringTokenizer tokenizer = new StringTokenizer(line, "$");
String fieldId = tokenizer.nextToken();
String complexName = tokenizer.nextToken();
ComplexName cName = new ComplexName(complexName);
String myName = cName.getName();
if ((fieldId.compareToIgnoreCase("STRUCT") == 0) ||
(fieldId.compareToIgnoreCase("UNION") == 0)) {
tokenizer.nextToken(); // size
tokenizer.nextToken(); // alignment
if (fieldId.compareToIgnoreCase("STRUCT") == 0) {
dt = new StructureDataType(cName.getCategoryPath(), myName, 0);
}
else {
dt = new UnionDataType(cName.getCategoryPath(), myName);
}
addDataType(dtMgr, dataTypes, dt);
int lastOffset = dt.getLength();
DataType member;
while (tokenizer.hasMoreElements()) {
String fieldName = tokenizer.nextToken();
String fieldType = tokenizer.nextToken();
String fieldOffset = tokenizer.nextToken();
String fieldSize = tokenizer.nextToken();
String fieldAlign = tokenizer.nextToken();
int align = valueOf(fieldAlign);
int fSize = valueOf(fieldSize);
int fOff = valueOf(fieldOffset);
ComplexName fType = new ComplexName(fieldType);
member = fType.getDataType(dtMgr, dataTypes);
try {
// If we don't know what this is, make something up
if ((member == null) || (member.getLength() < 0)) {
member = genUIData(dtMgr, fType, fOff - dt.getLength());
fSize = member.getLength();
}
// Zero length fields are OK if they're the last field (again we fake the size)
if (member.getLength() == 0) {
if (!tokenizer.hasMoreElements()) {
fType.count = 1;
member = fType.getDataType(dtMgr, dataTypes);
fSize = member.getLength();
}
}
if ((dt instanceof Structure) && ((fOff < dt.getLength()) ||
((fOff >= dt.getLength()) && (fSize < member.getLength())))) {
if (fOff >= dt.getLength()) {
lastOffset = dt.getLength();
((StructureDataType) dt).add(member, member.getLength(),
"_bit_fields_" + dt.getLength(), "");
}
DataTypeComponent dtc = ((StructureDataType) dt).getComponentAt(lastOffset);
String comment = dtc.getComment();
comment += " " + fieldName + "(" + fieldSize + ")";
dtc.setComment(comment);
if (fSize < member.getLength()) {
Msg.debug(this, "Dropping bitfield=[" + fieldName + "] type=[" +
member.getName() + "] in " + myName);
}
else {
Msg.debug(this, "Dropping element=[" + fieldName + "] type=[" +
member.getName() + "] in " + myName);
}
}
else {
// HACKALERT: Big ol' hack here... (GSL appears to be lying to us)
if (align > 4) {
align = 4;
}
int mod = (align == 0) ? 0 : dt.getLength() % align;
DataType modDt = null;
if (mod != 0) {
modDt = new ArrayDataType(new ByteDataType(), align - mod, 1);
}
if (member.getLength() > 0) {
lastOffset = dt.getLength();
if (modDt != null) {
((CompositeDataTypeImpl) dt).add(modDt, modDt.getLength(),
"_fill_" + dt.getLength(), ALIGNMENT_TAG);
}
((CompositeDataTypeImpl) dt).add(member, member.getLength(), fieldName,
"");
}
else {
Msg.debug(this, "Dropping mid-structure zero length element=[" +
fieldName + "] type=[" + member.getName() + "] in " + myName);
}
}
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
}
else if (fieldId.compareToIgnoreCase("FUNCTION") == 0) {
dt = new FunctionDefinitionDataType(cName.getCategoryPath(), cName.getName());
String retVal = tokenizer.nextToken();
ComplexName rvName = new ComplexName(retVal);
DataType rvDt = rvName.getDataType(dtMgr, dataTypes);
if (rvDt == null) {
rvDt = genUIData(dtMgr, rvName, 4);
}
((FunctionDefinitionDataType) dt).setReturnType(rvDt);
ArrayList<ParameterDefinition> parameters = new ArrayList<>();
index = 0;
while (tokenizer.hasMoreElements()) {
String fieldName = tokenizer.nextToken();
String fieldType = tokenizer.nextToken();
ComplexName fType = new ComplexName(fieldType);
DataType parameter = fType.getDataType(dtMgr, dataTypes);
if (parameter == null) {
parameter = genUIData(dtMgr, fType, 4);
}
parameters.add(new ParameterDefinitionImpl(fieldName, parameter, ""));
index++;
}
if (index > 0) {
ParameterDefinition[] parms = new ParameterDefinition[parameters.size()];
parameters.toArray(parms);
((FunctionDefinitionDataType) dt).setArguments(parms);
}
}
else if (fieldId.compareToIgnoreCase("TYPEDEF") == 0) {
String newName = tokenizer.nextToken();
try {
DataType baseType = cName.getDataType(dtMgr, dataTypes);
if (baseType == null) {
baseType = genUIData(dtMgr, cName, 4);
}
ComplexName cNewName = new ComplexName(newName);
dt = new TypedefDataType(cNewName.getCategoryPath(), newName, baseType);
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
else if (fieldId.compareToIgnoreCase("ENUM") == 0) {
ArrayList<String> fNames = new ArrayList<>();
ArrayList<String> fValues = new ArrayList<>();
ArrayList<String> fComments = new ArrayList<>();
while (tokenizer.hasMoreElements()) {
fNames.add(tokenizer.nextToken());
fValues.add(tokenizer.nextToken());
fComments.add(tokenizer.nextToken());
}
dt = new EnumDataType(cName.getCategoryPath(), cName.getName(), fNames.size(), null);
for (int i = 0; i < fNames.size(); i++) {
((EnumDataType) dt).add(fNames.get(i), new Long(fValues.get(i)).longValue(), fComments.get(i));
}
}
else if (fieldId.compareToIgnoreCase("SYMBOL") == 0) {
}
else {
Msg.warn(this, "What is this? " + fieldId);
}
return dt;
}
private void searchForErrors(FileDataTypeManager dtMgr) {
try {
Iterator<DataType> dts = dtMgr.getAllDataTypes();
while (dts.hasNext()) {
DataType dti = dts.next();
if (dti.getDisplayName().indexOf("%") >= 0) {
Msg.warn(this, "Misprocessed data type: " + dti.getDisplayName());
}
if (dti instanceof TypeDef) {
DataType base = ((TypeDef) dti).getBaseDataType();
if (base instanceof Pointer) {
base = ((Pointer) base).getDataType();
if (base.isEquivalent(dataUI)) {
Msg.warn(this, "Data type (" + dti.getDisplayName() + ") not found.");
}
}
}
}
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
public DataType genUIData(FileDataTypeManager dtMgr, ComplexName cName, int len) {
TypedefDataType dt = new TypedefDataType(cName.getCategoryPath(), cName.getName(),
new ArrayDataType(new ByteDataType(), len, 1));
addDataType(dtMgr, dataTypes, dt);
return dt;
}
int valueOf(String intString) {
return (new Integer(intString)).intValue() / 8;
}
private void addPrimitives(FileDataTypeManager dtMgr) {
addDataType(dtMgr, dataTypes, new TypedefDataType("char", new ByteDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("signed char", new ByteDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("unsigned char", new ByteDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("short", new WordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("short int", new WordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("short signed int", new WordDataType()));
addDataType(dtMgr, dataTypes,
new TypedefDataType("short unsigned int", new WordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("int", new DWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("long", new DWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("long int", new DWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("signed int", new DWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("unsigned int", new DWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("long signed int", new DWordDataType()));
addDataType(dtMgr, dataTypes,
new TypedefDataType("long unsigned int", new DWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("long long int", new QWordDataType()));
addDataType(dtMgr, dataTypes,
new TypedefDataType("long long signed int", new QWordDataType()));
addDataType(dtMgr, dataTypes,
new TypedefDataType("long long unsigned int", new QWordDataType()));
addDataType(dtMgr, dataTypes, new TypedefDataType("void", new VoidDataType()));
dataUI = new TypedefDataType("U/I", new DWordDataType());
addDataType(dtMgr, dataTypes, dataUI);
}
private void addDataType(FileDataTypeManager dtMgr, Hashtable<String, DataType> myDataTypes,
DataType dt) {
DataType type = dtMgr.addDataType(dt, DataTypeConflictHandler.REPLACE_HANDLER);
myDataTypes.put(type.getCategoryPath() + type.getName(), type);
}
private File chooseFile(Component parent, String title, String propertyName,
final String fileType) {
if (fileChooser == null) {
fileChooser = new GhidraFileChooser(parent);
}
fileChooser.setFileFilter(new ExtensionFileFilter(fileType,
fileType.toUpperCase() + " files (." + fileType + ")"));
fileChooser.setTitle(title);
// start the browsing in the user's preferred directory
//
File directory =
new File(Preferences.getProperty(propertyName, System.getProperty("user.home"), true));
fileChooser.setCurrentDirectory(directory);
fileChooser.setSelectedFile(directory);
File file = fileChooser.getSelectedFile();
if (file != null) {
// record where we last exported a file from to the user's preferences
Preferences.setProperty(propertyName, file.getAbsolutePath());
}
return file;
}
final static String NO_NAMESPACE = "/";
final int SIZE_X = 8;
final int ALIGNMENT = 32;
private void writeAsGsl(File file, DataTypeManager dtMgr, TaskMonitor monitor) {
String out = "";
int count = 0;
try {
FileOutputStream stream = new FileOutputStream(file);
Iterator<DataType> it = dtMgr.getAllDataTypes();
while (it.hasNext()) {
DataType dt = it.next();
out = "";
if (dt instanceof Composite) {
out = writeComposite(stream, dt);
}
else if (dt instanceof TypeDef) {
out = writeTypeDef(stream, (TypeDef) dt);
}
else if (dt instanceof FunctionDefinition) {
out = writeFunctionDefinition(stream, (FunctionDefinition) dt);
}
else if (dt instanceof Enum) {
out = writeEnum(stream, (Enum) dt);
}
else {
Msg.debug(this, "Something went wrong while printing GSL output...");
}
if (out != "") {
stream.write(out.getBytes());
}
if (count % 100 == 0) {
monitor.setProgress(count);
}
count++;
}
stream.close();
}
catch (Exception e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
private String writeComposite(FileOutputStream stream, DataType dt) {
String out;
DataTypeComponent[] components;
out = (dt instanceof Structure) ? "STRUCT$" : "UNION$";
components = ((Composite) dt).getComponents();
out += new NameComplex(dt).getGSLName() + "$";
out += SIZE_X * dt.getLength() + "$";
out += ALIGNMENT;
for (DataTypeComponent component : components) {
String comment = component.getComment();
if ((comment != null) && (comment.compareTo(ALIGNMENT_TAG) != 0)) {
NameComplex cComp = new NameComplex(component.getDataType());
out += "$";
out += component.getFieldName() + "$";
out += cComp.getGSLName() + "$";
out += SIZE_X * component.getOffset() + "$";
out += SIZE_X * component.getLength() + "$";
if (component.getDataType() instanceof Composite) {
out += ALIGNMENT;
}
else {
out += SIZE_X * cComp.getBaseTypeSize();
}
}
}
out += "\n";
return out;
}
private String writeTypeDef(FileOutputStream stream, TypeDef def) {
DataType dt = def.getDataType();
String out = "TYPEDEF$";
out += new NameComplex(dt).getGSLName() + "$";
out += new NameComplex(def).getGSLName() + "\n";
return out;
}
private String writeEnum(FileOutputStream stream, Enum enuum) {
String out = "ENUM$";
String[] names = enuum.getNames();
long[] values = enuum.getValues();
out += new NameComplex(enuum).getGSLName();
for (int i = 0; i < names.length; i++) {
out += "$";
out += names[i] + "$";
out += values[i];
}
out += "\n";
return out;
}
private String writeFunctionDefinition(FileOutputStream stream, FunctionDefinition fn) {
String out = "FUNCTION$";
ParameterDefinition[] parameters = fn.getArguments();
DataType ret = fn.getReturnType();
out += new NameComplex(fn).getGSLName() + "$";
out += new NameComplex(ret).getGSLName();
for (ParameterDefinition parameter : parameters) {
NameComplex cParm = new NameComplex(parameter.getDataType());
out += "$";
String pName = parameter.getName();
out += ((pName.compareToIgnoreCase(" ") == 0) ? "" : pName);
out += "$";
out += cParm.getGSLName();
}
out += "\n";
return out;
}
public class NameComplex {
DataType dt;
String myName;
String dtNamespace;
int baseTypeSize;
public NameComplex(DataType dt) {
this.dt = dt;
dtNamespace = dt.getCategoryPath().getPath();
DataType base = dt;
boolean shouldDescend = false;
myName = "";
if (dt instanceof Pointer) {
myName = "Pointer%";
base = ((Pointer) dt).getDataType();
shouldDescend = true;
}
else if (dt instanceof Array) {
Array array = (Array) dt;
myName =
"Array%" + array.getNumElements() + "%" + (SIZE_X * array.getLength() + "%");
base = array.getDataType();
shouldDescend = true;
}
if (shouldDescend) {
NameComplex cName = new NameComplex(base);
myName += cName.getGSLName();
if (dt instanceof Pointer) {
baseTypeSize = dt.getLength();
}
else {
baseTypeSize = cName.getBaseTypeSize();
}
}
else {
if (dtNamespace.compareToIgnoreCase(NO_NAMESPACE) != 0) {
myName += dtNamespace + ":";
}
myName += dt.getName();
baseTypeSize = dt.getLength();
}
}
public String getGSLName() {
return myName;
}
public int getBaseTypeSize() {
return baseTypeSize;
}
}
}

View file

@ -1,141 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on Aug 9, 2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package ghidra.app.plugin.prototype.dataArchiveUtilities;
import ghidra.program.model.data.*;
import ghidra.util.Msg;
import java.util.Hashtable;
public class ComplexName {
boolean isPointer;
boolean isArray;
boolean usesNamespace;
String complexName;
String namespace;
String name;
int count = 1;
public ComplexName(String complexName) {
this.complexName = complexName;
if (complexName.startsWith("Pointer%")) {
isPointer = true;
complexName = complexName.substring(complexName.indexOf("%")+1);
}
if (complexName.startsWith("Array%")) {
isArray = true;
complexName = complexName.substring(complexName.indexOf("%")+1);
String countStr = complexName.substring(0, complexName.indexOf("%"));
if (countStr.compareToIgnoreCase("") != 0) {
count = new Integer(countStr).intValue();
} else {
count = 1;
}
complexName = complexName.substring(complexName.indexOf("%")+1);
complexName = complexName.substring(complexName.indexOf("%")+1);
}
usesNamespace = (complexName.indexOf(":") >= 0);
if (usesNamespace) {
namespace = complexName.substring(complexName.indexOf("/"), complexName.indexOf(":"));
name = complexName.substring(0, complexName.indexOf("/"))+
complexName.substring(complexName.indexOf(":")+1, complexName.length());
} else {
namespace = "";
name = complexName;
}
}
public boolean isArray() {
return isArray;
}
public boolean isPointer() {
return isPointer;
}
public String getName() {
return name;
}
public String getNamespace() {
return namespace;
}
public boolean usesNamespace() {
return usesNamespace;
}
public CategoryPath getCategoryPath() {
return (usesNamespace ? new CategoryPath(namespace) : CategoryPath.ROOT);
}
public DataType getDataType(FileDataTypeManager dtMgr, Hashtable<String,DataType> dataTypes) {
return getDataType(dtMgr, dataTypes, true);
}
public DataType getDataType(DataTypeManager dtMgr, Hashtable<String,DataType> dataTypes, boolean generateUI) {
DataType dt;
if (name.indexOf("%") >= 0) {
ComplexName cName = new ComplexName(name);
dt = cName.getDataType(dtMgr, dataTypes, generateUI);
name = cName.getName();
} else {
if (dataTypes == null) {
dt = dtMgr.getDataType(getCategoryPath(), getName());
} else {
dt = dataTypes.get(getCategoryPath()+getName());
}
//if (dt == null) {
// dt = dtMgr.getDataType(getCategoryPath(), getName());
//}
}
if (dt == null) {
if (generateUI) {
// Add placeholders for the archive entries that are missing
dt = genUIData(dtMgr, dataTypes, new ComplexName(complexName), 4);
} else {
Msg.warn(this, "Data type ("+name+") not found.");
return dt;
}
}
if (isPointer) {
dt = new Pointer32DataType(dt);
}
if (isArray) {
if (dt.getLength() >= 0) {
dt = new ArrayDataType(dt, count, dt.getLength());
} else {
Msg.error(this, "Error in array length ("+dt.getLength()+") for "+dt.getName());
return null;
}
}
return dt;
}
public DataType genUIData(DataTypeManager dtMgr, Hashtable<String,DataType> dataTypes, ComplexName cName, int len) {
TypedefDataType dt = new TypedefDataType(cName.getCategoryPath(), cName.getName(),
new ArrayDataType(new ByteDataType(), len, 1));
addDataType(dtMgr, dataTypes, dt);
return dt;
}
private void addDataType(DataTypeManager dtMgr, Hashtable<String,DataType> dataTypes, DataType dt) {
DataType type = dtMgr.addDataType(dt, DataTypeConflictHandler.REPLACE_HANDLER);
dataTypes.put(type.getCategoryPath()+type.getName(), type);
}
}

View file

@ -40,8 +40,7 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
// private constructor for making diff copies // private constructor for making diff copies
private EnumDataTypeHTMLRepresentation(Enum enumDataType, List<ValidatableLine> headerLines, private EnumDataTypeHTMLRepresentation(Enum enumDataType, List<ValidatableLine> headerLines,
TextLine displayName, TextLine displayName, List<ValidatableLine> bodyContent, TextLine footerLine) {
List<ValidatableLine> bodyContent, TextLine footerLine) {
this.enumDataType = enumDataType; this.enumDataType = enumDataType;
this.headerContent = headerLines; this.headerContent = headerLines;
this.displayName = displayName; this.displayName = displayName;
@ -113,7 +112,13 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
int length = hexString.length(); int length = hexString.length();
hexString = hexString.substring(length - (n * 2)); hexString = hexString.substring(length - (n * 2));
} }
list.add(new TextLine(name + " = 0x" + hexString));
String comment = enumDataType.getComment(name);
if (trim && comment != null) {
comment = StringUtilities.trim(comment, ToolTipUtils.LINE_LENGTH);
}
list.add(new TextLine(name + " = 0x" + hexString + " " + comment));
} }
return list; return list;
@ -147,7 +152,7 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
displayNameText = HTMLUtilities.friendlyEncodeHTML(displayNameText); displayNameText = HTMLUtilities.friendlyEncodeHTML(displayNameText);
displayNameText = wrapStringInColor(displayNameText, displayName.getTextColor()); displayNameText = wrapStringInColor(displayNameText, displayName.getTextColor());
//@formatter:off //@formatter:off
append(fullHtml, truncatedHtml, lineCount, TT_OPEN, append(fullHtml, truncatedHtml, lineCount, TT_OPEN,
displayNameText, displayNameText,
TT_CLOSE, TT_CLOSE,
HTML_SPACE, HTML_SPACE,
@ -192,8 +197,8 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
return fullHtml.toString(); return fullHtml.toString();
} }
private static void append(StringBuilder fullHtml, StringBuilder truncatedHtml, private static void append(StringBuilder fullHtml, StringBuilder truncatedHtml, int lineCount,
int lineCount, String... content) { String... content) {
for (String string : content) { for (String string : content) {
fullHtml.append(string); fullHtml.append(string);
@ -247,8 +252,7 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
diffDisplayName, bodyDiff.getLeftLines(), footerLine), diffDisplayName, bodyDiff.getLeftLines(), footerLine),
new EnumDataTypeHTMLRepresentation(enumRepresentation.enumDataType, new EnumDataTypeHTMLRepresentation(enumRepresentation.enumDataType,
headerDiff.getRightLines(), otherDiffDisplayName, bodyDiff.getRightLines(), headerDiff.getRightLines(), otherDiffDisplayName, bodyDiff.getRightLines(),
enumRepresentation.footerLine) enumRepresentation.footerLine) };
};
} }
} }

View file

@ -70,7 +70,7 @@ public abstract class HTMLDataTypeRepresentation {
// Note 1: Indentation tags (note: we switched from <DIV> tags because the Java rendering engine // Note 1: Indentation tags (note: we switched from <DIV> tags because the Java rendering engine
// does not keep the color of the div's parent tags. The <P> tag seems to work). // does not keep the color of the div's parent tags. The <P> tag seems to work).
// Note 2: Switch back to <DIV> from <P>, since the <P> tag gets broken by the <TABLE> tag // Note 2: Switch back to <DIV> from <P>, since the <P> tag gets broken by the <TABLE> tag
// used by composite types. If not inheriting the color becomes an issue, then we will need // used by composite types. If not inheriting the color becomes an issue, then we will need
// to find another solution for indentation. // to find another solution for indentation.
protected static final String INDENT_OPEN = "<DIV STYLE='margin-left: 10px;'>"; protected static final String INDENT_OPEN = "<DIV STYLE='margin-left: 10px;'>";
protected static final String INDENT_CLOSE = "</DIV>"; protected static final String INDENT_CLOSE = "</DIV>";
@ -87,7 +87,7 @@ public abstract class HTMLDataTypeRepresentation {
protected final static Color DIFF_COLOR = ValidatableLine.INVALID_COLOR; protected final static Color DIFF_COLOR = ValidatableLine.INVALID_COLOR;
private static String createSpace(int numberOfSpaces) { private static String createSpace(int numberOfSpaces) {
StringBuffer buffer = new StringBuffer(); StringBuilder buffer = new StringBuilder();
for (int i = 0; i < numberOfSpaces; i++) { for (int i = 0; i < numberOfSpaces; i++) {
buffer.append(HTML_SPACE); buffer.append(HTML_SPACE);
} }
@ -134,7 +134,7 @@ public abstract class HTMLDataTypeRepresentation {
* Returns the plain-text value of the data type's description. * Returns the plain-text value of the data type's description.
* <p> * <p>
* If there were html tags in the string, they are escaped. * If there were html tags in the string, they are escaped.
* *
* @param dataType the type to get the description / comment for * @param dataType the type to get the description / comment for
* @return plain-text string, w/html escaped * @return plain-text string, w/html escaped
*/ */
@ -167,7 +167,7 @@ public abstract class HTMLDataTypeRepresentation {
/** /**
* Formats a multi-line plain-text comment string into a HTML string where the text has been * Formats a multi-line plain-text comment string into a HTML string where the text has been
* wrapped at MAX_LINE_LENGTH. * wrapped at MAX_LINE_LENGTH.
* *
* @param string plain-text string * @param string plain-text string
* @return list of html strings * @return list of html strings
*/ */
@ -241,9 +241,9 @@ public abstract class HTMLDataTypeRepresentation {
/** /**
* Formats a multi-line plain-text comment as a list of HTML marked-up lines. * Formats a multi-line plain-text comment as a list of HTML marked-up lines.
* *
* @param comment multi-line plain-text string * @param comment multi-line plain-text string
* @param maxLines max number of formatted lines to return * @param maxLines max number of formatted lines to return
* @return list of html marked-up {@link TextLine}s * @return list of html marked-up {@link TextLine}s
*/ */
protected static List<TextLine> createCommentLines(String comment, int maxLines) { protected static List<TextLine> createCommentLines(String comment, int maxLines) {
@ -325,9 +325,9 @@ public abstract class HTMLDataTypeRepresentation {
} }
/** /**
* Returns an HTML string for this data representation object. The HTML returned will be * Returns an HTML string for this data representation object. The HTML returned will be
* truncated if it is too long. To get the full HTML, call {@link #getFullHTMLString()}. * truncated if it is too long. To get the full HTML, call {@link #getFullHTMLString()}.
* *
* @return the html * @return the html
* @see #getFullHTMLString() * @see #getFullHTMLString()
*/ */
@ -337,7 +337,7 @@ public abstract class HTMLDataTypeRepresentation {
/** /**
* Returns an HTML string for this data representation object * Returns an HTML string for this data representation object
* *
* @return the html * @return the html
* @see #getHTMLString() * @see #getHTMLString()
*/ */
@ -345,16 +345,16 @@ public abstract class HTMLDataTypeRepresentation {
return HTML_OPEN + originalHTMLData + HTML_CLOSE; return HTML_OPEN + originalHTMLData + HTML_CLOSE;
} }
/** /**
* This is like {@link #getHTMLString()}, but does not put HTML tags around the data * This is like {@link #getHTMLString()}, but does not put HTML tags around the data
* @return the content * @return the content
*/ */
public String getHTMLContentString() { public String getHTMLContentString() {
return originalHTMLData; // default to full text; subclasses can override return originalHTMLData; // default to full text; subclasses can override
} }
/** /**
* This is like {@link #getHTMLString()}, but does not put HTML tags around the data * This is like {@link #getHTMLString()}, but does not put HTML tags around the data
* @return the content * @return the content
*/ */
public String getFullHTMLContentString() { public String getFullHTMLContentString() {

View file

@ -1115,12 +1115,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
@Test @Test
public void testEditEnum() throws Exception { public void testEditEnum() throws Exception {
// edit DLL_Table in latest; edit DLL_Table in private
// only DLL_Table should be in conflict; not the ones where it is used.
mtf.initialize("notepad", new ProgramModifierListener() { mtf.initialize("notepad", new ProgramModifierListener() {
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -1140,9 +1136,6 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
} }
} }
/* (non-Javadoc)
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void modifyPrivate(ProgramDB program) { public void modifyPrivate(ProgramDB program) {
boolean commit = false; boolean commit = false;
@ -1180,7 +1173,164 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertNotNull(dt); assertNotNull(dt);
Enum enumm = (Enum) dt; Enum enumm = (Enum) dt;
assertEquals(0x10, enumm.getValue("Pink")); assertEquals(0x10, enumm.getValue("Pink"));
}
@Test
public void testEditEnumComments_NoConflict_CommentAddedInLatest() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
try {
Enum enumm = (Enum) dt;
String valueName = "Pink";
long value = enumm.getValue(valueName);
enumm.remove(valueName);
enumm.add(valueName, value, "This is the latest comment on server");
commit = true;
}
finally {
program.endTransaction(transactionID, commit);
}
}
@Override
public void modifyPrivate(ProgramDB program) {
// no change
}
});
executeMerge(DataTypeMergeManager.OPTION_MY);
DataTypeManager dtm = resultProgram.getDataTypeManager();
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
assertNotNull(dt);
Enum enumm = (Enum) dt;
assertEquals(0x3, enumm.getValue("Pink"));
assertEquals("This is the latest comment on server", enumm.getComment("Pink"));
}
@Test
public void testEditEnumComments_Conflict_TakeMyChanges() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
try {
Enum enumm = (Enum) dt;
String valueName = "Pink";
long value = enumm.getValue(valueName);
enumm.remove(valueName);
enumm.add(valueName, value, "This is the latest comment on server");
commit = true;
}
finally {
program.endTransaction(transactionID, commit);
}
}
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
try {
Enum enumm = (Enum) dt;
String valueName = "Pink";
long value = enumm.getValue(valueName);
enumm.remove(valueName);
enumm.add(valueName, value, "This my local updated comment");
commit = true;
}
finally {
program.endTransaction(transactionID, commit);
}
}
});
executeMerge(DataTypeMergeManager.OPTION_MY);
DataTypeManager dtm = resultProgram.getDataTypeManager();
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
assertNotNull(dt);
Enum enumm = (Enum) dt;
assertEquals(0x3, enumm.getValue("Pink"));
assertEquals("This my local updated comment", enumm.getComment("Pink"));
}
@Test
public void testEditEnumComments_Conflict_TakeLatestChanges() throws Exception {
mtf.initialize("notepad", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
try {
Enum enumm = (Enum) dt;
String valueName = "Pink";
long value = enumm.getValue(valueName);
enumm.remove(valueName);
enumm.add(valueName, value, "This is the latest comment on server");
commit = true;
}
finally {
program.endTransaction(transactionID, commit);
}
}
@Override
public void modifyPrivate(ProgramDB program) {
boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test");
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
try {
Enum enumm = (Enum) dt;
String valueName = "Pink";
long value = enumm.getValue(valueName);
enumm.remove(valueName);
enumm.add(valueName, value, "This my local updated comment");
commit = true;
}
finally {
program.endTransaction(transactionID, commit);
}
}
});
executeMerge(DataTypeMergeManager.OPTION_LATEST);
DataTypeManager dtm = resultProgram.getDataTypeManager();
Category c = dtm.getCategory(new CategoryPath("/MISC"));
DataType dt = c.getDataType("FavoriteColors");
assertNotNull(dt);
Enum enumm = (Enum) dt;
assertEquals(0x3, enumm.getValue("Pink"));
assertEquals("This is the latest comment on server", enumm.getComment("Pink"));
} }
@Test @Test
@ -1355,9 +1505,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
try { try {
fd.setReturnType(bar); fd.setReturnType(bar);
@ -1376,9 +1525,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
@ -1423,9 +1571,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
try { try {
fd.setReturnType(bar); fd.setReturnType(bar);
@ -1446,9 +1593,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
@ -1491,9 +1637,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
try { try {
fd.setVarArgs(true); fd.setVarArgs(true);
@ -1514,9 +1659,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
@ -1560,9 +1704,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
try { try {
fd.setVarArgs(true); fd.setVarArgs(true);
@ -1583,9 +1726,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
@ -1633,9 +1775,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
try { try {
fd.setReturnType(VoidDataType.dataType); fd.setReturnType(VoidDataType.dataType);
@ -1655,9 +1796,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
boolean commit = false; boolean commit = false;
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
FunctionDefinition fd = FunctionDefinition fd = (FunctionDefinition) dtm
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
"MyFunctionDef");
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
int transactionID = program.startTransaction("test"); int transactionID = program.startTransaction("test");

View file

@ -77,8 +77,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
public void testEnumFields() throws Exception { public void testEnumFields() throws Exception {
Category c = program.getListing() Category c = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(c, "TestEnum", 1); Enum enumm = createEnum(c, "TestEnum", 1);
edit(enumm); edit(enumm);
@ -132,8 +131,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
public void testEnumSize1() throws Exception { public void testEnumSize1() throws Exception {
Category category = program.getListing() Category category = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(category, "TestEnum", 1); Enum enumm = createEnum(category, "TestEnum", 1);
edit(enumm); edit(enumm);
@ -184,8 +182,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
// test entering too large a value // test entering too large a value
Category category = program.getListing() Category category = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(category, "TestEnum", 1); Enum enumm = createEnum(category, "TestEnum", 1);
edit(enumm); edit(enumm);
@ -228,8 +225,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
public void testEnumSize4BadInput() throws Exception { public void testEnumSize4BadInput() throws Exception {
Category category = program.getListing() Category category = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(category, "MyTestEnum", 4); Enum enumm = createEnum(category, "MyTestEnum", 4);
edit(enumm); edit(enumm);
@ -280,8 +276,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
public void testBadInputForValue() throws Exception { public void testBadInputForValue() throws Exception {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(cat, "TestEnum", 1); Enum enumm = createEnum(cat, "TestEnum", 1);
edit(enumm); edit(enumm);
@ -310,8 +305,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 1); enumm.add("Green", 1);
@ -375,8 +369,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
public void testValueForNewEntry() throws Exception { public void testValueForNewEntry() throws Exception {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0x10); enumm.add("Red", 0x10);
enumm.add("Green", 0x20); enumm.add("Green", 0x20);
@ -656,7 +649,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
EnumEditorPanel panel = findEditorPanel(tool.getToolFrame()); EnumEditorPanel panel = findEditorPanel(tool.getToolFrame());
JTable table = panel.getTable(); JTable table = panel.getTable();
// //
// First, let's try forward then backward // First, let's try forward then backward
// //
int startRow = 1; int startRow = 1;
@ -665,12 +658,18 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
Component c = getEditorComponent(editor); Component c = getEditorComponent(editor);
triggerActionKey(c, 0, KeyEvent.VK_TAB); triggerActionKey(c, 0, KeyEvent.VK_TAB);
editor = assertEditingCell(table, startRow, startCol + 1);
c = getEditorComponent(editor);
triggerActionKey(c, 0, KeyEvent.VK_TAB);
editor = assertEditingCell(table, startRow, startCol + 2);
c = getEditorComponent(editor);
triggerActionKey(c, InputEvent.SHIFT_DOWN_MASK, KeyEvent.VK_TAB);
editor = assertEditingCell(table, startRow, startCol + 1); editor = assertEditingCell(table, startRow, startCol + 1);
c = getEditorComponent(editor); c = getEditorComponent(editor);
triggerActionKey(c, InputEvent.SHIFT_DOWN_MASK, KeyEvent.VK_TAB); triggerActionKey(c, InputEvent.SHIFT_DOWN_MASK, KeyEvent.VK_TAB);
editor = assertEditingCell(table, startRow, startCol); editor = assertEditingCell(table, startRow, startCol);
c = getEditorComponent(editor); c = getEditorComponent(editor);
@ -678,7 +677,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
// Now, let's try going around the world and back // Now, let's try going around the world and back
// //
int lastRow = 2; int lastRow = 2;
int lastCol = 1; int lastCol = 2;
editor = startEditTableCell(table, lastRow, lastCol); editor = startEditTableCell(table, lastRow, lastCol);
c = getEditorComponent(editor); c = getEditorComponent(editor);
@ -703,7 +702,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
JTable table = getEditTable(); JTable table = getEditTable();
// //
// First, let's try up and down // First, let's try up and down
// //
int startRow = 0; int startRow = 0;
@ -739,7 +738,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testNewEnumFromAction() throws Exception { public void testNewEnumFromAction() throws Exception {
// //
// This test works differently that the others in that it uses the same path as the // This test works differently that the others in that it uses the same path as the
// GUI action to start the editing process. // GUI action to start the editing process.
// //
DataTypeManager dtm = program.getListing().getDataTypeManager(); DataTypeManager dtm = program.getListing().getDataTypeManager();
@ -764,8 +763,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
Category category = program.getListing() Category category = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(category, "EnumX", 2); Enum enumm = createEnum(category, "EnumX", 2);
int transactionID = program.startTransaction("Test"); int transactionID = program.startTransaction("Test");
@ -835,8 +833,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
Category category = program.getListing() Category category = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = createEnum(category, "EnumX", 2); Enum enumm = createEnum(category, "EnumX", 2);
int transactionID = program.startTransaction("Test"); int transactionID = program.startTransaction("Test");
@ -1049,8 +1046,8 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
try { try {
Category category = dtm.getCategory(enummDt.getCategoryPath()); Category category = dtm.getCategory(enummDt.getCategoryPath());
Category parentCategory = category.getParent(); Category parentCategory = category.getParent();
assertTrue("Did not remove category", parentCategory.removeCategory(category.getName(), assertTrue("Did not remove category",
TaskMonitor.DUMMY)); parentCategory.removeCategory(category.getName(), TaskMonitor.DUMMY));
} }
finally { finally {
program.endTransaction(txID, true); program.endTransaction(txID, true);
@ -1126,8 +1123,8 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
private TableCellEditor assertEditingCell(final JTable table, final int row, final int col) { private TableCellEditor assertEditingCell(final JTable table, final int row, final int col) {
Pair<Integer, Integer> rowCol = getEditingCell(table); Pair<Integer, Integer> rowCol = getEditingCell(table);
assertEquals(row, (int) rowCol.first); assertEquals("Not editing expected row", row, (int) rowCol.first);
assertEquals(col, (int) rowCol.second); assertEquals("Not editing expected column", col, (int) rowCol.second);
return runSwing(() -> table.getCellEditor()); return runSwing(() -> table.getCellEditor());
} }
@ -1144,8 +1141,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
private Enum createRedGreenBlueEnum() { private Enum createRedGreenBlueEnum() {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 1); enumm.add("Green", 1);
@ -1235,7 +1231,7 @@ public class EnumEditor1Test extends AbstractGhidraHeadedIntegrationTest {
addEnumValue(); addEnumValue();
waitForSwing(); waitForSwing();
final int row = model.getRowCount() - 1; final int row = model.getRowCount() - 1;
// change entry // change entry
table.addRowSelectionInterval(row, row); table.addRowSelectionInterval(row, row);
Rectangle rect = table.getCellRect(row, NAME_COL, true); Rectangle rect = table.getCellRect(row, NAME_COL, true);
clickMouse(table, 1, rect.x, rect.y, 2, 0); clickMouse(table, 1, rect.x, rect.y, 2, 0);

View file

@ -41,10 +41,6 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env; private TestEnv env;
private DataTypeManagerPlugin plugin; private DataTypeManagerPlugin plugin;
public EnumEditor2Test() {
super();
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -70,8 +66,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 0x10); enumm.add("Green", 0x10);
@ -107,8 +102,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
public void testSortColumns() throws Exception { public void testSortColumns() throws Exception {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 0x10); enumm.add("Green", 0x10);
@ -151,8 +145,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
public void testSortOrder() throws Exception { public void testSortOrder() throws Exception {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 0x10); enumm.add("Green", 0x10);
@ -197,8 +190,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
public void testInsertRowByName() throws Exception { public void testInsertRowByName() throws Exception {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 0x10); enumm.add("Green", 0x10);
@ -324,8 +316,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
waitForSwing(); waitForSwing();
} }
final ComponentProvider provider = final ComponentProvider provider = waitForComponentProvider(EnumEditorProvider.class);
waitForComponentProvider(EnumEditorProvider.class);
assertNotNull(provider); assertNotNull(provider);
SwingUtilities.invokeLater(() -> provider.closeComponent()); SwingUtilities.invokeLater(() -> provider.closeComponent());
waitForSwing(); waitForSwing();
@ -360,8 +351,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
waitForSwing(); waitForSwing();
} }
final ComponentProvider provider = final ComponentProvider provider = waitForComponentProvider(EnumEditorProvider.class);
waitForComponentProvider(EnumEditorProvider.class);
assertNotNull(provider); assertNotNull(provider);
SwingUtilities.invokeLater(() -> provider.closeComponent()); SwingUtilities.invokeLater(() -> provider.closeComponent());
waitForSwing(); waitForSwing();
@ -390,8 +380,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
waitForSwing(); waitForSwing();
} }
final ComponentProvider provider = final ComponentProvider provider = waitForComponentProvider(EnumEditorProvider.class);
waitForComponentProvider(EnumEditorProvider.class);
assertNotNull(provider); assertNotNull(provider);
SwingUtilities.invokeLater(() -> provider.closeComponent()); SwingUtilities.invokeLater(() -> provider.closeComponent());
waitForSwing(); waitForSwing();
@ -455,8 +444,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 0x10); enumm.add("Green", 0x10);
@ -760,7 +748,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
}); });
waitForSwing(); waitForSwing();
final int newRow = model.getRowCount() - 1; final int newRow = model.getRowCount() - 1;
// change entry // change entry
runSwing(() -> table.addRowSelectionInterval(newRow, newRow)); runSwing(() -> table.addRowSelectionInterval(newRow, newRow));
Rectangle rect = table.getCellRect(newRow, EnumTableModel.NAME_COL, true); Rectangle rect = table.getCellRect(newRow, EnumTableModel.NAME_COL, true);
clickMouse(table, 1, rect.x, rect.y, 2, 0); clickMouse(table, 1, rect.x, rect.y, 2, 0);
@ -828,8 +816,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
private Enum editSampleEnum() { private Enum editSampleEnum() {
Category cat = program.getListing() Category cat = program.getListing()
.getDataTypeManager() .getDataTypeManager()
.getCategory( .getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
new CategoryPath(CategoryPath.ROOT, "Category1"));
final Enum enumm = new EnumDataType("Colors", 1); final Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0); enumm.add("Red", 0);
enumm.add("Green", 0x10); enumm.add("Green", 0x10);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,8 @@ import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; import java.util.*;
import org.apache.commons.lang3.StringUtils;
import db.DBRecord; import db.DBRecord;
import db.Field; import db.Field;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
@ -33,7 +35,6 @@ import ghidra.util.UniversalID;
/** /**
* Database implementation for the enumerated data type. * Database implementation for the enumerated data type.
*
*/ */
class EnumDB extends DataTypeDB implements Enum { class EnumDB extends DataTypeDB implements Enum {
@ -42,6 +43,7 @@ class EnumDB extends DataTypeDB implements Enum {
private EnumDBAdapter adapter; private EnumDBAdapter adapter;
private EnumValueDBAdapter valueAdapter; private EnumValueDBAdapter valueAdapter;
private Map<String, Long> nameMap; // name to value private Map<String, Long> nameMap; // name to value
private Map<Long, List<String>> valueMap; // value to names private Map<Long, List<String>> valueMap; // value to names
private Map<String, String> commentMap; // name to comment private Map<String, String> commentMap; // name to comment
@ -88,21 +90,22 @@ class EnumDB extends DataTypeDB implements Enum {
commentMap = new HashMap<>(); commentMap = new HashMap<>();
Field[] ids = valueAdapter.getValueIdsInEnum(key); Field[] ids = valueAdapter.getValueIdsInEnum(key);
for (Field id : ids) { for (Field id : ids) {
DBRecord rec = valueAdapter.getRecord(id.getLongValue()); DBRecord rec = valueAdapter.getRecord(id.getLongValue());
String valueName = rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL); String valueName = rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL);
long value = rec.getLongValue(EnumValueDBAdapter.ENUMVAL_VALUE_COL); long value = rec.getLongValue(EnumValueDBAdapter.ENUMVAL_VALUE_COL);
String valueNameComment = rec.getString(EnumValueDBAdapter.ENUMVAL_COMMENT_COL); String comment = rec.getString(EnumValueDBAdapter.ENUMVAL_COMMENT_COL);
addToCache(valueName, value, valueNameComment); addToCache(valueName, value, comment);
} }
} }
private void addToCache(String valueName, long value, String valueNameComment) { private void addToCache(String valueName, long value, String comment) {
nameMap.put(valueName, value); nameMap.put(valueName, value);
List<String> list = valueMap.computeIfAbsent(value, v -> new ArrayList<>()); List<String> list = valueMap.computeIfAbsent(value, v -> new ArrayList<>());
list.add(valueName); list.add(valueName);
commentMap.put(valueName, valueNameComment); if (!StringUtils.isBlank(comment)) {
commentMap.put(valueName, comment);
}
} }
private boolean removeFromCache(String valueName) { private boolean removeFromCache(String valueName) {
@ -121,10 +124,7 @@ class EnumDB extends DataTypeDB implements Enum {
if (list.isEmpty()) { if (list.isEmpty()) {
valueMap.remove(value); valueMap.remove(value);
} }
String comment = commentMap.remove(valueName); commentMap.remove(valueName);
if (comment == null) {
return false;
}
return true; return true;
} }
@ -168,7 +168,7 @@ class EnumDB extends DataTypeDB implements Enum {
} }
@Override @Override
public String getComment(String valueName) throws NoSuchElementException { public String getComment(String valueName) {
lock.acquire(); lock.acquire();
try { try {
checkIsValid(); checkIsValid();
@ -214,19 +214,6 @@ class EnumDB extends DataTypeDB implements Enum {
} }
} }
@Override
public String[] getComments() {
lock.acquire();
try {
checkIsValid();
initializeIfNeeded();
return commentMap.keySet().toArray(new String[commentMap.size()]);
}
finally {
lock.release();
}
}
@Override @Override
public int getCount() { public int getCount() {
lock.acquire(); lock.acquire();
@ -242,12 +229,11 @@ class EnumDB extends DataTypeDB implements Enum {
@Override @Override
public void add(String valueName, long value) { public void add(String valueName, long value) {
String valueNameComment = ""; add(valueName, value, null);
add(valueName, value, valueNameComment);
} }
@Override @Override
public void add(String valueName, long value, String valueNameComment) { public void add(String valueName, long value, String comment) {
lock.acquire(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
@ -256,10 +242,15 @@ class EnumDB extends DataTypeDB implements Enum {
if (nameMap.containsKey(valueName)) { if (nameMap.containsKey(valueName)) {
throw new IllegalArgumentException(valueName + " already exists in this enum"); throw new IllegalArgumentException(valueName + " already exists in this enum");
} }
if (StringUtils.isBlank(comment)) {
comment = null; // use null values in the db to save space
}
bitGroups = null; bitGroups = null;
valueAdapter.createRecord(key, valueName, value, valueNameComment); valueAdapter.createRecord(key, valueName, value, comment);
adapter.updateRecord(record, true); adapter.updateRecord(record, true);
addToCache(valueName, value, valueNameComment); addToCache(valueName, value, comment);
dataMgr.dataTypeChanged(this, false); dataMgr.dataTypeChanged(this, false);
} }
catch (IOException e) { catch (IOException e) {
@ -294,10 +285,9 @@ class EnumDB extends DataTypeDB implements Enum {
if (!removeFromCache(valueName)) { if (!removeFromCache(valueName)) {
return; return;
} }
bitGroups = null; bitGroups = null;
Field[] ids = valueAdapter.getValueIdsInEnum(key); Field[] ids = valueAdapter.getValueIdsInEnum(key);
for (Field id : ids) { for (Field id : ids) {
DBRecord rec = valueAdapter.getRecord(id.getLongValue()); DBRecord rec = valueAdapter.getRecord(id.getLongValue());
if (valueName.equals(rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL))) { if (valueName.equals(rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL))) {
@ -321,6 +311,7 @@ class EnumDB extends DataTypeDB implements Enum {
if (!(dataType instanceof Enum)) { if (!(dataType instanceof Enum)) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
Enum enumm = (Enum) dataType; Enum enumm = (Enum) dataType;
lock.acquire(); lock.acquire();
try { try {
@ -338,19 +329,21 @@ class EnumDB extends DataTypeDB implements Enum {
int oldLength = getLength(); int oldLength = getLength();
int newLength = enumm.getLength(); int newLength = enumm.getLength();
if (oldLength != newLength) { if (oldLength != newLength) {
record.setByteValue(EnumDBAdapter.ENUM_SIZE_COL, (byte) newLength); record.setByteValue(EnumDBAdapter.ENUM_SIZE_COL, (byte) newLength);
adapter.updateRecord(record, true); adapter.updateRecord(record, true);
} }
String[] names = enumm.getNames(); String[] names = enumm.getNames();
for (String name2 : names) { for (String valueName : names) {
long value = enumm.getValue(name2); long value = enumm.getValue(valueName);
String comment = enumm.getComment(name2); String comment = enumm.getComment(valueName);
valueAdapter.createRecord(key, name2, value, comment); if (StringUtils.isBlank(comment)) {
comment = null; // use null values in the db to save space
}
valueAdapter.createRecord(key, valueName, value, comment);
adapter.updateRecord(record, true); adapter.updateRecord(record, true);
addToCache(name2, value, comment); addToCache(valueName, value, comment);
} }
if (oldLength != newLength) { if (oldLength != newLength) {
@ -525,7 +518,7 @@ class EnumDB extends DataTypeDB implements Enum {
return "0"; return "0";
} }
List<BitGroup> list = getBitGroups(); List<BitGroup> list = getBitGroups();
StringBuffer buf = new StringBuffer(); StringBuilder buf = new StringBuilder();
for (BitGroup bitGroup : list) { for (BitGroup bitGroup : list) {
long subValue = bitGroup.getMask() & value; long subValue = bitGroup.getMask() & value;
if (subValue != 0) { if (subValue != 0) {
@ -576,21 +569,39 @@ class EnumDB extends DataTypeDB implements Enum {
getLength() != enumm.getLength() || getCount() != enumm.getCount()) { getLength() != enumm.getLength() || getCount() != enumm.getCount()) {
return false; return false;
} }
if (!isEachValueEquivalent(enumm)) {
return false;
}
return true;
}
private boolean isEachValueEquivalent(Enum enumm) {
String[] names = getNames(); String[] names = getNames();
String[] otherNames = enumm.getNames(); String[] otherNames = enumm.getNames();
try { try {
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
if (!names[i].equals(otherNames[i])) {
return false;
}
long value = getValue(names[i]); long value = getValue(names[i]);
long otherValue = enumm.getValue(names[i]); long otherValue = enumm.getValue(names[i]);
if (!names[i].equals(otherNames[i]) || value != otherValue) { if (value != otherValue) {
return false;
}
String comment = getComment(names[i]);
String otherComment = enumm.getComment(names[i]);
if (!comment.equals(otherComment)) {
return false; return false;
} }
} }
return true;
} }
catch (NoSuchElementException e) { catch (NoSuchElementException e) {
return false; // named element not found return false; // named element not found
} }
return true;
} }
@Override @Override
@ -598,6 +609,7 @@ class EnumDB extends DataTypeDB implements Enum {
try { try {
nameMap = null; nameMap = null;
valueMap = null; valueMap = null;
commentMap = null;
bitGroups = null; bitGroups = null;
DBRecord rec = adapter.getRecord(key); DBRecord rec = adapter.getRecord(key);
if (rec != null) { if (rec != null) {
@ -731,5 +743,4 @@ class EnumDB extends DataTypeDB implements Enum {
lock.release(); lock.release();
} }
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -30,15 +30,16 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Adapter to access the Enumeration data type values tables. * Adapter to access the Enumeration data type values tables.
*/ */
abstract class EnumValueDBAdapter { abstract class EnumValueDBAdapter implements RecordTranslator {
static final String ENUM_VALUE_TABLE_NAME = "Enumeration Values"; static final String ENUM_VALUE_TABLE_NAME = "Enumeration Values";
static final Schema ENUM_VALUE_SCHEMA = EnumValueDBAdapterV0.V0_ENUM_VALUE_SCHEMA; static final Schema ENUM_VALUE_SCHEMA = EnumValueDBAdapterV1.SCHEMA;
// Enum Value Columns // Enum Value Columns
static final int ENUMVAL_NAME_COL = EnumValueDBAdapterV0.V0_ENUMVAL_NAME_COL; static final int ENUMVAL_NAME_COL = 0;
static final int ENUMVAL_VALUE_COL = EnumValueDBAdapterV0.V0_ENUMVAL_VALUE_COL; static final int ENUMVAL_VALUE_COL = 1;
static final int ENUMVAL_ID_COL = EnumValueDBAdapterV0.V0_ENUMVAL_ID_COL; static final int ENUMVAL_ID_COL = 2;
static final int ENUMVAL_COMMENT_COL = EnumValueDBAdapterV0.V0_ENUMVAL_COMMENT_COL; static final int ENUMVAL_COMMENT_COL = 3;
/** /**
* Gets an adapter for working with the enumeration data type values database table. The adapter is based * Gets an adapter for working with the enumeration data type values database table. The adapter is based
@ -53,16 +54,16 @@ abstract class EnumValueDBAdapter {
static EnumValueDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor) static EnumValueDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
throws VersionException, IOException { throws VersionException, IOException {
if (openMode == DBConstants.CREATE) { if (openMode == DBConstants.CREATE) {
return new EnumValueDBAdapterV0(handle, true); return new EnumValueDBAdapterV1(handle, true);
} }
try { try {
return new EnumValueDBAdapterV0(handle, false); return new EnumValueDBAdapterV1(handle, false);
} }
catch (VersionException e) { catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) { if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
throw e; throw e;
} }
EnumValueDBAdapter adapter = new EnumValueDBAdapterNoTable(handle); EnumValueDBAdapter adapter = findReadOnlyAdapter(handle);
if (openMode == DBConstants.UPGRADE) { if (openMode == DBConstants.UPGRADE) {
adapter = upgrade(handle, adapter); adapter = upgrade(handle, adapter);
} }
@ -70,8 +71,18 @@ abstract class EnumValueDBAdapter {
} }
} }
static EnumValueDBAdapter findReadOnlyAdapter(DBHandle handle) {
try {
return new EnumValueDBAdapterV0(handle);
}
catch (VersionException e) {
return new EnumValueDBAdapterNoTable(handle);
}
}
/** /**
* Upgrades the Enumeration Data Type Values table from the oldAdapter's version to the current version. * Upgrades the Enumeration Data Type Values table from the oldAdapter's version to the current
* version.
* @param handle handle to the database whose table is to be upgraded to a newer version. * @param handle handle to the database whose table is to be upgraded to a newer version.
* @param oldAdapter the adapter for the existing table to be upgraded. * @param oldAdapter the adapter for the existing table to be upgraded.
* @return the adapter for the new upgraded version of the table. * @return the adapter for the new upgraded version of the table.
@ -81,7 +92,30 @@ abstract class EnumValueDBAdapter {
*/ */
static EnumValueDBAdapter upgrade(DBHandle handle, EnumValueDBAdapter oldAdapter) static EnumValueDBAdapter upgrade(DBHandle handle, EnumValueDBAdapter oldAdapter)
throws VersionException, IOException { throws VersionException, IOException {
return new EnumValueDBAdapterV0(handle, true);
DBHandle tmpHandle = new DBHandle();
long id = tmpHandle.startTransaction();
EnumValueDBAdapter tmpAdapter = null;
try {
tmpAdapter = new EnumValueDBAdapterV1(tmpHandle, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec);
}
oldAdapter.deleteTable(handle);
EnumValueDBAdapter newAdapter = new EnumValueDBAdapterV1(handle, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
DBRecord rec = it.next();
newAdapter.updateRecord(rec);
}
return newAdapter;
}
finally {
tmpHandle.endTransaction(id, true);
tmpHandle.close();
}
} }
/** /**
@ -90,7 +124,7 @@ abstract class EnumValueDBAdapter {
* @param name value name * @param name value name
* @param value numeric value * @param value numeric value
* @param comment the field comment * @param comment the field comment
* @throws IOException if IO error occurs * @throws IOException if there was a problem accessing the database
*/ */
abstract void createRecord(long enumID, String name, long value, String comment) abstract void createRecord(long enumID, String name, long value, String comment)
throws IOException; throws IOException;
@ -99,10 +133,26 @@ abstract class EnumValueDBAdapter {
* Get enum value record which corresponds to specified value record ID * Get enum value record which corresponds to specified value record ID
* @param valueID value record ID * @param valueID value record ID
* @return value record or null * @return value record or null
* @throws IOException if IO error occurs * @throws IOException if there was a problem accessing the database
*/ */
abstract DBRecord getRecord(long valueID) throws IOException; abstract DBRecord getRecord(long valueID) throws IOException;
/**
* Returns an iterator over the value records inside of this Enum
* @return the iterator
* @throws IOException if there was a problem accessing the database
*/
abstract RecordIterator getRecords() throws IOException;
/**
* Deletes the table; used when upgrading
* @param handle the handle used to delete the table
* @throws IOException if there was a problem accessing the database
*/
void deleteTable(DBHandle handle) throws IOException {
handle.deleteTable(ENUM_VALUE_TABLE_NAME);
}
/** /**
* Remove the record for the given enum Value ID. * Remove the record for the given enum Value ID.
* @param valueID ID of the value record to delete * @param valueID ID of the value record to delete
@ -113,7 +163,7 @@ abstract class EnumValueDBAdapter {
/** /**
* Updates the enum data type values table with the provided record. * Updates the enum data type values table with the provided record.
* @param record the new record * @param record the new record
* @throws IOException if the database can't be accessed. * @throws IOException if there was a problem accessing the database
*/ */
abstract void updateRecord(DBRecord record) throws IOException; abstract void updateRecord(DBRecord record) throws IOException;
@ -121,8 +171,7 @@ abstract class EnumValueDBAdapter {
* Get enum value record IDs which correspond to specified enum datatype ID * Get enum value record IDs which correspond to specified enum datatype ID
* @param enumID enum datatype ID * @param enumID enum datatype ID
* @return enum value record IDs as LongField values within Field array * @return enum value record IDs as LongField values within Field array
* @throws IOException if IO error occurs * @throws IOException if there was a problem accessing the database
*/ */
abstract Field[] getValueIdsInEnum(long enumID) throws IOException; abstract Field[] getValueIdsInEnum(long enumID) throws IOException;
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,7 +17,10 @@ package ghidra.program.database.data;
import java.io.IOException; import java.io.IOException;
import javax.help.UnsupportedOperationException;
import db.*; import db.*;
import ghidra.program.database.util.EmptyRecordIterator;
/** /**
* Adapter needed for a read-only version of data type manager that is not going * Adapter needed for a read-only version of data type manager that is not going
@ -59,4 +62,18 @@ class EnumValueDBAdapterNoTable extends EnumValueDBAdapter {
return Field.EMPTY_ARRAY; return Field.EMPTY_ARRAY;
} }
@Override
RecordIterator getRecords() throws IOException {
return new EmptyRecordIterator();
}
@Override
protected void deleteTable(DBHandle handle) throws IOException {
// do nothing
}
@Override
public DBRecord translateRecord(DBRecord rec) {
throw new UnsupportedOperationException();
}
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,92 +18,84 @@ package ghidra.program.database.data;
import java.io.IOException; import java.io.IOException;
import db.*; import db.*;
import ghidra.program.model.lang.ConstantPool.Record;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
/** /**
* Version 0 implementation for the enumeration tables adapter. * Version 0 implementation for the enumeration tables adapter.
*
*/ */
class EnumValueDBAdapterV0 extends EnumValueDBAdapter { class EnumValueDBAdapterV0 extends EnumValueDBAdapter {
static final int VERSION = 0; static final int VERSION = 0;
// Enum Value Columns // Keep for reference
static final int V0_ENUMVAL_NAME_COL = 0; // static final Schema SCHEMA = new Schema(0, "Enum Value ID",
static final int V0_ENUMVAL_VALUE_COL = 1; // new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
static final int V0_ENUMVAL_ID_COL = 2; // new String[] { "Name", "Value", "Enum ID" });
static final int V0_ENUMVAL_COMMENT_COL = 3;
static final Schema V0_ENUM_VALUE_SCHEMA = new Schema(0, "Enum Value ID", private Table table;
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
new String[] { "Name", "Value", "Enum ID" });
// static final Schema V1_ENUM_VALUE_SCHEMA = new Schema(0, "Enum Value ID",
// new Class[] { StringField.class, LongField.class, LongField.class, StringField.class },
// new String[] { "Name", "Value", "Enum ID", "Comment" });
private Table valueTable;
/** /**
* Gets a version 0 adapter for the Enumeration Data Type Values database table. * Gets a version 0 adapter for the Enumeration Data Type Values database table.
* @param handle handle to the database containing the table. * @param handle handle to the database containing the table.
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version * @throws VersionException if the the table's version does not match the expected version
* for this adapter. * for this adapter.
* @throws IOException if IO error occurs
*/ */
public EnumValueDBAdapterV0(DBHandle handle, boolean create) public EnumValueDBAdapterV0(DBHandle handle) throws VersionException {
throws VersionException, IOException {
if (create) { table = handle.getTable(ENUM_VALUE_TABLE_NAME);
valueTable = handle.createTable(ENUM_VALUE_TABLE_NAME, V0_ENUM_VALUE_SCHEMA, if (table == null) {
new int[] { V0_ENUMVAL_ID_COL }); throw new VersionException("Missing Table: " + ENUM_VALUE_TABLE_NAME);
} }
else {
valueTable = handle.getTable(ENUM_VALUE_TABLE_NAME); int version = table.getSchema().getVersion();
if (valueTable == null) { if (version != VERSION) {
throw new VersionException("Missing Table: " + ENUM_VALUE_TABLE_NAME); String msg = "Expected version " + VERSION + " for table " + ENUM_VALUE_TABLE_NAME +
} " but got " + table.getSchema().getVersion();
int version = valueTable.getSchema().getVersion(); throw new VersionException(msg, VersionException.NEWER_VERSION, false);
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + ENUM_VALUE_TABLE_NAME +
" but got " + valueTable.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
}
} }
} }
@Override @Override
public void createRecord(long enumID, String name, long value, String comment) public void createRecord(long enumID, String name, long value, String comment)
throws IOException { throws IOException {
Record record = V0_ENUM_VALUE_SCHEMA.createRecord(valueTable.getKey()); throw new UnsupportedOperationException("Cannot update Version 0");
record.setLongValue(V0_ENUMVAL_ID_COL, enumID);
record.setString(V0_ENUMVAL_NAME_COL, name);
record.setLongValue(V0_ENUMVAL_VALUE_COL, value);
record.setString(V0_ENUMVAL_COMMENT_COL, comment);
valueTable.putRecord(record);
} }
@Override @Override
public DBRecord getRecord(long valueID) throws IOException { public DBRecord getRecord(long valueID) throws IOException {
return valueTable.getRecord(valueID); return translateRecord(table.getRecord(valueID));
} }
@Override @Override
public void removeRecord(long valueID) throws IOException { public void removeRecord(long valueID) throws IOException {
valueTable.deleteRecord(valueID); throw new UnsupportedOperationException("Cannot remove Version 0");
} }
@Override @Override
public void updateRecord(DBRecord record) throws IOException { public void updateRecord(DBRecord record) throws IOException {
valueTable.putRecord(record); throw new UnsupportedOperationException("Cannot update Version 0");
} }
@Override @Override
public Field[] getValueIdsInEnum(long enumID) throws IOException { public Field[] getValueIdsInEnum(long enumID) throws IOException {
return valueTable.findRecords(new LongField(enumID), V0_ENUMVAL_ID_COL); return table.findRecords(new LongField(enumID), ENUMVAL_ID_COL);
}
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
return null;
}
DBRecord record = EnumValueDBAdapter.ENUM_VALUE_SCHEMA.createRecord(oldRec.getKey());
record.setLongValue(ENUMVAL_ID_COL, oldRec.getLongValue(ENUMVAL_ID_COL));
record.setString(ENUMVAL_NAME_COL, oldRec.getString(ENUMVAL_NAME_COL));
record.setLongValue(ENUMVAL_VALUE_COL, oldRec.getLongValue(ENUMVAL_VALUE_COL));
record.setString(ENUMVAL_COMMENT_COL, null);
return record;
}
@Override
RecordIterator getRecords() throws IOException {
return new TranslatedRecordIterator(table.iterator(), this);
} }
} }

View file

@ -0,0 +1,107 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
import java.io.IOException;
import db.*;
import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for the enumeration tables adapter.
*/
class EnumValueDBAdapterV1 extends EnumValueDBAdapter {
static final int VERSION = 1;
static final Schema SCHEMA = new Schema(VERSION, "Enum Value ID",
new Class[] { StringField.class, LongField.class, LongField.class, StringField.class },
new String[] { "Name", "Value", "Enum ID", "Comment" });
private Table table;
/**
* Gets a version 1 adapter for the Enumeration Data Type Values database table.
* @param handle handle to the database containing the table.
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
public EnumValueDBAdapterV1(DBHandle handle, boolean create)
throws VersionException, IOException {
if (create) {
table = handle.createTable(ENUM_VALUE_TABLE_NAME, SCHEMA, new int[] { ENUMVAL_ID_COL });
}
else {
table = handle.getTable(ENUM_VALUE_TABLE_NAME);
if (table == null) {
throw new VersionException(true);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + ENUM_VALUE_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
}
}
}
@Override
public void createRecord(long enumID, String name, long value, String comment)
throws IOException {
DBRecord record = SCHEMA.createRecord(table.getKey());
record.setLongValue(ENUMVAL_ID_COL, enumID);
record.setString(ENUMVAL_NAME_COL, name);
record.setLongValue(ENUMVAL_VALUE_COL, value);
record.setString(ENUMVAL_COMMENT_COL, comment);
table.putRecord(record);
}
@Override
public DBRecord getRecord(long valueID) throws IOException {
return table.getRecord(valueID);
}
@Override
public void removeRecord(long valueID) throws IOException {
table.deleteRecord(valueID);
}
@Override
public void updateRecord(DBRecord record) throws IOException {
table.putRecord(record);
}
@Override
public Field[] getValueIdsInEnum(long enumID) throws IOException {
return table.findRecords(new LongField(enumID), ENUMVAL_ID_COL);
}
@Override
RecordIterator getRecords() throws IOException {
return table.iterator();
}
@Override
public DBRecord translateRecord(DBRecord r) {
return r;
}
}

View file

@ -24,9 +24,9 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Adapter to access the Pointer database table for Pointer data types. * Adapter to access the Pointer database table for Pointer data types.
* *
*/ */
abstract class PointerDBAdapter { abstract class PointerDBAdapter implements RecordTranslator {
static final String POINTER_TABLE_NAME = "Pointers"; static final String POINTER_TABLE_NAME = "Pointers";
static final Schema SCHEMA = new Schema(PointerDBAdapterV2.VERSION, "Pointer ID", static final Schema SCHEMA = new Schema(PointerDBAdapterV2.VERSION, "Pointer ID",
@ -96,7 +96,7 @@ abstract class PointerDBAdapter {
} }
/** /**
* *
*/ */
abstract void deleteTable(DBHandle handle) throws IOException; abstract void deleteTable(DBHandle handle) throws IOException;
@ -105,6 +105,7 @@ abstract class PointerDBAdapter {
* @param dataTypeID data type ID of the date type being pointed to * @param dataTypeID data type ID of the date type being pointed to
* @param categoryID the category ID of the datatype * @param categoryID the category ID of the datatype
* @param length pointer size in bytes * @param length pointer size in bytes
* @return the record
* @throws IOException if there was a problem accessing the database * @throws IOException if there was a problem accessing the database
*/ */
abstract DBRecord createRecord(long dataTypeID, long categoryID, int length) throws IOException; abstract DBRecord createRecord(long dataTypeID, long categoryID, int length) throws IOException;
@ -117,6 +118,11 @@ abstract class PointerDBAdapter {
*/ */
abstract DBRecord getRecord(long pointerID) throws IOException; abstract DBRecord getRecord(long pointerID) throws IOException;
/**
* An iterator over the records of this adapter
* @return the iterator
* @throws IOException if there was a problem accessing the database
*/
abstract RecordIterator getRecords() throws IOException; abstract RecordIterator getRecords() throws IOException;
/** /**
@ -135,51 +141,11 @@ abstract class PointerDBAdapter {
abstract void updateRecord(DBRecord record) throws IOException; abstract void updateRecord(DBRecord record) throws IOException;
/** /**
* Gets all the pointer data types that are contained in the category that * Gets all the pointer data types that are contained in the category that
* have the indicated ID. * have the indicated ID.
* @param categoryID the category whose pointer data types are wanted. * @param categoryID the category whose pointer data types are wanted.
* @return an array of IDs for the pointer data types in the category. * @return an array of IDs for the pointer data types in the category.
* @throws IOException if the database can't be accessed. * @throws IOException if the database can't be accessed.
*/ */
abstract Field[] getRecordIdsInCategory(long categoryID) throws IOException; abstract Field[] getRecordIdsInCategory(long categoryID) throws IOException;
DBRecord translateRecord(DBRecord rec) {
return rec;
}
class TranslatedRecordIterator implements RecordIterator {
private RecordIterator it;
TranslatedRecordIterator(RecordIterator it) {
this.it = it;
}
@Override
public boolean delete() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean hasNext() throws IOException {
return it.hasNext();
}
@Override
public boolean hasPrevious() throws IOException {
return it.hasPrevious();
}
@Override
public DBRecord next() throws IOException {
DBRecord rec = it.next();
return translateRecord(rec);
}
@Override
public DBRecord previous() throws IOException {
DBRecord rec = it.previous();
return translateRecord(rec);
}
}
} }

View file

@ -22,14 +22,15 @@ import ghidra.util.exception.VersionException;
/** /**
* Version 0 implementation for the accessing the pointer database table. * Version 0 implementation for the accessing the pointer database table.
* *
*/ */
class PointerDBAdapterV0 extends PointerDBAdapter { class PointerDBAdapterV0 extends PointerDBAdapter {
final static int VERSION = 0; final static int VERSION = 0;
static final int OLD_PTR_DTD_COL = 0; static final int V0_PTR_DTD_COL_ = 0;
static final int OLD_PTR_SIZE_COL = 1; static final int V0_PTR_SIZE_COL = 1;
// Keep for reference
// static final Schema SCHEMA = new Schema(VERSION, "Pointer ID", // static final Schema SCHEMA = new Schema(VERSION, "Pointer ID",
// new Class[] {LongField.class, IntField.class}, // new Class[] {LongField.class, IntField.class},
// new String[] {"Data Type ID", "Size"}); // new String[] {"Data Type ID", "Size"});
@ -60,7 +61,7 @@ class PointerDBAdapterV0 extends PointerDBAdapter {
@Override @Override
RecordIterator getRecords() throws IOException { RecordIterator getRecords() throws IOException {
return new TranslatedRecordIterator(table.iterator()); return new TranslatedRecordIterator(table.iterator(), this);
} }
@Override @Override
@ -79,13 +80,14 @@ class PointerDBAdapterV0 extends PointerDBAdapter {
} }
@Override @Override
DBRecord translateRecord(DBRecord oldRec) { public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) { if (oldRec == null) {
return null; return null;
} }
DBRecord rec = PointerDBAdapter.SCHEMA.createRecord(oldRec.getKey()); DBRecord rec = PointerDBAdapter.SCHEMA.createRecord(oldRec.getKey());
rec.setLongValue(PTR_DT_ID_COL, oldRec.getLongValue(OLD_PTR_DTD_COL)); rec.setLongValue(PTR_DT_ID_COL, oldRec.getLongValue(V0_PTR_DTD_COL_));
rec.setLongValue(PTR_CATEGORY_COL, 0); rec.setLongValue(PTR_CATEGORY_COL, 0);
rec.setByteValue(PTR_LENGTH_COL, (byte) -1);
return rec; return rec;
} }

View file

@ -26,11 +26,13 @@ import ghidra.util.exception.VersionException;
class PointerDBAdapterV1 extends PointerDBAdapter { class PointerDBAdapterV1 extends PointerDBAdapter {
final static int VERSION = 1; final static int VERSION = 1;
static final int OLD_PTR_DT_ID_COL = 0; static final int V1_PTR_DT_ID_COL = 0;
static final int OLD_PTR_CATEGORY_COL = 1; static final int V1_PTR_CATEGORY_COL = 1;
static final Schema V1_SCHEMA =
new Schema(VERSION, "Pointer ID", new Field[] { LongField.INSTANCE, LongField.INSTANCE }, // Keep for reference
new String[] { "Data Type ID", "Category ID" }); // static final Schema V1_SCHEMA =
// new Schema(VERSION, "Pointer ID", new Field[] { LongField.INSTANCE, LongField.INSTANCE },
// new String[] { "Data Type ID", "Category ID" });
private Table table; private Table table;
@ -49,13 +51,13 @@ class PointerDBAdapterV1 extends PointerDBAdapter {
} }
@Override @Override
DBRecord translateRecord(DBRecord oldRec) { public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) { if (oldRec == null) {
return null; return null;
} }
DBRecord rec = PointerDBAdapter.SCHEMA.createRecord(oldRec.getKey()); DBRecord rec = PointerDBAdapter.SCHEMA.createRecord(oldRec.getKey());
rec.setLongValue(PTR_DT_ID_COL, oldRec.getLongValue(OLD_PTR_DT_ID_COL)); rec.setLongValue(PTR_DT_ID_COL, oldRec.getLongValue(V1_PTR_DT_ID_COL));
rec.setLongValue(PTR_CATEGORY_COL, oldRec.getLongValue(OLD_PTR_CATEGORY_COL)); rec.setLongValue(PTR_CATEGORY_COL, oldRec.getLongValue(V1_PTR_CATEGORY_COL));
rec.setByteValue(PTR_LENGTH_COL, (byte) -1); rec.setByteValue(PTR_LENGTH_COL, (byte) -1);
return rec; return rec;
} }
@ -72,7 +74,7 @@ class PointerDBAdapterV1 extends PointerDBAdapter {
@Override @Override
RecordIterator getRecords() throws IOException { RecordIterator getRecords() throws IOException {
return new TranslatedRecordIterator(table.iterator()); return new TranslatedRecordIterator(table.iterator(), this);
} }
@Override @Override
@ -87,7 +89,7 @@ class PointerDBAdapterV1 extends PointerDBAdapter {
@Override @Override
Field[] getRecordIdsInCategory(long categoryID) throws IOException { Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), OLD_PTR_CATEGORY_COL); return table.findRecords(new LongField(categoryID), V1_PTR_CATEGORY_COL);
} }
@Override @Override

View file

@ -86,7 +86,10 @@ class PointerDBAdapterV2 extends PointerDBAdapter {
@Override @Override
void deleteTable(DBHandle handle) throws IOException { void deleteTable(DBHandle handle) throws IOException {
handle.deleteTable(POINTER_TABLE_NAME); handle.deleteTable(POINTER_TABLE_NAME);
} }
@Override
public DBRecord translateRecord(DBRecord rec) {
return rec;
}
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,16 +15,15 @@
*/ */
package ghidra.program.database.map; package ghidra.program.database.map;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import db.DBConstants; import db.DBConstants;
import db.DBHandle; import db.DBHandle;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
/** /**
* Database adapter for address map * Database adapter for address map

View file

@ -24,9 +24,9 @@ public interface Enum extends DataType {
/** /**
* Get the value for the given name. * Get the value for the given name.
* @param name name of the entry * @param name name of the entry.
* @return the value * @return the value.
* @throws NoSuchElementException if the name does not exist in this Enum * @throws NoSuchElementException if the name does not exist in this Enum.
*/ */
public long getValue(String name) throws NoSuchElementException; public long getValue(String name) throws NoSuchElementException;
@ -39,11 +39,11 @@ public interface Enum extends DataType {
/** /**
* Get the comment for the given name. * Get the comment for the given name.
* @param name name of the entry * @param name name of the entry.
* @return the comment * @return the comment or the empty string if the name does not exist in this enum or if no
* @throws NoSuchElementException if the name does not exist in this Enum * comment is set.
*/ */
public String getComment(String name) throws NoSuchElementException; public String getComment(String name);
/** /**
* Get the values of the enum entries. * Get the values of the enum entries.
@ -52,17 +52,15 @@ public interface Enum extends DataType {
public long[] getValues(); public long[] getValues();
/** /**
* Get the names of the enum entries. * Get the names of the enum entries. The returned names are sorted using String's natural
* sort order.
* @return the names of the enum entries.
*/ */
public String[] getNames(); public String[] getNames();
/** /**
* Get the comments of the enum entries. * Get the number of entries in this Enum.
*/ * @return the number of entries in this Enum.
public String[] getComments();
/**
* Get the number of entries in this Enum.
*/ */
public int getCount(); public int getCount();
@ -82,14 +80,14 @@ public interface Enum extends DataType {
public void add(String name, long value, String comment); public void add(String name, long value, String comment);
/** /**
* Remove the enum entry with the given name. * Remove the enum entry with the given name.
* @param name name of entry to remove. * @param name name of entry to remove.
*/ */
public void remove(String name); public void remove(String name);
/** /**
* Set the description for this Enum. * Set the description for this Enum.
* @param description * @param description the description
*/ */
@Override @Override
public void setDescription(String description); public void setDescription(String description);
@ -98,6 +96,7 @@ public interface Enum extends DataType {
* Get enum representation of the big-endian value. * Get enum representation of the big-endian value.
* @param bigInt BigInteger value with the appropriate sign * @param bigInt BigInteger value with the appropriate sign
* @param settings integer format settings (PADDING, FORMAT, etc.) * @param settings integer format settings (PADDING, FORMAT, etc.)
* @param bitLength the bit length
* @return formatted integer string * @return formatted integer string
*/ */
public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength); public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,6 +18,8 @@ package ghidra.program.model.data;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; import java.util.*;
import org.apache.commons.lang3.StringUtils;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition; import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.database.data.DataTypeUtilities;
@ -95,12 +97,12 @@ public class EnumDataType extends GenericDataType implements Enum {
} }
@Override @Override
public String getComment(String valueName) throws NoSuchElementException { public String getComment(String valueName) {
String valueNameComment = commentMap.get(valueName); String comment = commentMap.get(valueName);
if (valueNameComment == null) { if (comment == null) {
valueNameComment = ""; comment = "";
} }
return valueNameComment; return comment;
} }
@Override @Override
@ -117,11 +119,6 @@ public class EnumDataType extends GenericDataType implements Enum {
return names; return names;
} }
@Override
public String[] getComments() {
return commentMap.values().toArray(new String[commentMap.size()]);
}
@Override @Override
public int getCount() { public int getCount() {
return nameMap.size(); return nameMap.size();
@ -129,28 +126,25 @@ public class EnumDataType extends GenericDataType implements Enum {
@Override @Override
public void add(String valueName, long value) { public void add(String valueName, long value) {
String valueNameComment = ""; add(valueName, value, null);
add(valueName, value, valueNameComment);
} }
@Override @Override
public void add(String valueName, long value, String valueNameComment) { public void add(String valueName, long value, String comment) {
bitGroups = null; bitGroups = null;
checkValue(value); checkValue(value);
if (nameMap.containsKey(valueName)) { if (nameMap.containsKey(valueName)) {
throw new IllegalArgumentException(valueName + " already exists in this enum"); throw new IllegalArgumentException(valueName + " already exists in this enum");
} }
nameMap.put(valueName, value); nameMap.put(valueName, value);
List<String> list = valueMap.get(value); List<String> list = valueMap.computeIfAbsent(value, v -> new ArrayList<>());
if (list == null) {
list = new ArrayList<>();
valueMap.put(value, list);
}
list.add(valueName); list.add(valueName);
if (valueNameComment == null) {
valueNameComment = ""; if (!StringUtils.isBlank(comment)) {
commentMap.put(valueName, comment);
} }
commentMap.put(valueName, valueNameComment);
} }
private void checkValue(long value) { private void checkValue(long value) {
@ -180,21 +174,24 @@ public class EnumDataType extends GenericDataType implements Enum {
public void remove(String valueName) { public void remove(String valueName) {
bitGroups = null; bitGroups = null;
Long value = nameMap.get(valueName); Long value = nameMap.get(valueName);
if (value != null) { if (value == null) {
nameMap.remove(valueName); return;
List<String> list = valueMap.get(value);
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
if (valueName.equals(iter.next())) {
iter.remove();
break;
}
}
if (list.isEmpty()) {
valueMap.remove(value);
}
commentMap.remove(valueName);
} }
nameMap.remove(valueName);
List<String> list = valueMap.get(value);
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
if (valueName.equals(iter.next())) {
iter.remove();
break;
}
}
if (list.isEmpty()) {
valueMap.remove(value);
}
commentMap.remove(valueName);
} }
@Override @Override
@ -231,11 +228,11 @@ public class EnumDataType extends GenericDataType implements Enum {
public void setLength(int length) { public void setLength(int length) {
String[] names = getNames(); String[] names = getNames();
for (String enumName : names) { for (String valueName : names) {
long value = getValue(enumName); long value = getValue(valueName);
if (isTooBig(length, value)) { if (isTooBig(length, value)) {
throw new IllegalArgumentException("Setting the length of this Enum to a size " + throw new IllegalArgumentException("Setting the length of this Enum to a size " +
"that cannot contain the current value for \"" + enumName + "\" of " + "that cannot contain the current value for \"" + valueName + "\" of " +
Long.toHexString(value)); Long.toHexString(value));
} }
} }
@ -327,7 +324,7 @@ public class EnumDataType extends GenericDataType implements Enum {
return "0"; return "0";
} }
List<BitGroup> list = getBitGroups(); List<BitGroup> list = getBitGroups();
StringBuffer buf = new StringBuffer(); StringBuilder buf = new StringBuilder();
for (BitGroup bitGroup : list) { for (BitGroup bitGroup : list) {
long subValue = bitGroup.getMask() & value; long subValue = bitGroup.getMask() & value;
if (subValue != 0) { if (subValue != 0) {
@ -372,30 +369,45 @@ public class EnumDataType extends GenericDataType implements Enum {
if (dt == null || !(dt instanceof Enum)) { if (dt == null || !(dt instanceof Enum)) {
return false; return false;
} }
Enum enumm = (Enum) dt;
Enum enumm = (Enum) dt;
if (!DataTypeUtilities.equalsIgnoreConflict(name, enumm.getName()) || if (!DataTypeUtilities.equalsIgnoreConflict(name, enumm.getName()) ||
length != enumm.getLength() || getCount() != enumm.getCount()) { length != enumm.getLength() || getCount() != enumm.getCount()) {
return false; return false;
} }
if (!isEachValueEquivalent(enumm)) {
return false;
}
return true;
}
private boolean isEachValueEquivalent(Enum enumm) {
String[] names = getNames(); String[] names = getNames();
String[] otherNames = enumm.getNames(); String[] otherNames = enumm.getNames();
try { try {
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
if (!names[i].equals(otherNames[i])) {
return false;
}
long value = getValue(names[i]); long value = getValue(names[i]);
long otherValue = enumm.getValue(names[i]); long otherValue = enumm.getValue(names[i]);
if (value != otherValue) {
return false;
}
String comment = getComment(names[i]); String comment = getComment(names[i]);
String otherComment = enumm.getComment(names[i]); String otherComment = enumm.getComment(names[i]);
if (!names[i].equals(otherNames[i]) || value != otherValue || if (!comment.equals(otherComment)) {
!comment.equals(otherComment)) {
return false; return false;
} }
} }
return true;
} }
catch (NoSuchElementException e) { catch (NoSuchElementException e) {
return false; // named element not found return false; // named element not found
} }
return true;
} }
@Override @Override
@ -410,14 +422,14 @@ public class EnumDataType extends GenericDataType implements Enum {
commentMap = new HashMap<>(); commentMap = new HashMap<>();
setLength(enumm.getLength()); setLength(enumm.getLength());
String[] names = enumm.getNames(); String[] names = enumm.getNames();
for (String name2 : names) { for (String valueName : names) {
add(name2, enumm.getValue(name2), enumm.getComment(name2)); add(valueName, enumm.getValue(valueName), enumm.getComment(valueName));
} }
stateChanged(null); stateChanged(null);
} }
@Override @Override
public String getDefaultLabelPrefix() { public String getDefaultLabelPrefix() {
return name == null ? null : name.toUpperCase(); return name;
} }
} }

View file

@ -66,7 +66,7 @@ public class DataTypeEditorsScreenShots extends GhidraScreenShotGenerator {
dataTypeWindows.add(dataTypeDialog); dataTypeWindows.add(dataTypeDialog);
captureComponents(dataTypeWindows); captureComponents(dataTypeWindows);
closeAllWindowsAndFrames(); closeAllWindows();
} }
private DropDownSelectionTextField<?> showTypeChooserDialog() throws Exception { private DropDownSelectionTextField<?> showTypeChooserDialog() throws Exception {
@ -189,7 +189,7 @@ public class DataTypeEditorsScreenShots extends GhidraScreenShotGenerator {
waitForSwing(); waitForSwing();
captureDialog(); captureDialog();
closeAllWindowsAndFrames(); closeAllWindows();
} }
@Test @Test