mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-17 08:00:15 +00:00
GT-3415 Added mutability setting to enum datatypes as well as some code
cleanup.
This commit is contained in:
parent
ccabecec3a
commit
3ea8770bae
@ -46,6 +46,7 @@ import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.test.*;
|
||||
@ -1264,6 +1265,8 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||
assertNotNull("Expected data type: " + dtName, d);
|
||||
assertTrue("Expected data type: " + dtName, expectedDataType.isInstance(d.getDataType()));
|
||||
|
||||
DataType dt = d.getDataType();
|
||||
|
||||
boolean onByteWordData = true;
|
||||
boolean onFloatDoubleData = true;
|
||||
boolean onCharData = true;
|
||||
@ -1280,7 +1283,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||
// || expectedDataType.equals(StringDataType.class)
|
||||
// || expectedDataType.equals(UnicodeDataType.class));
|
||||
|
||||
boolean hasSettings = d.getDataType().getSettingsDefinitions().length != 0;
|
||||
boolean hasSettings = dt.getSettingsDefinitions().length != 0;
|
||||
|
||||
String caseName = "On " + dtName + " at: " + getCurrentLocation();
|
||||
|
||||
@ -1294,7 +1297,8 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||
|
||||
checkAction(actions, CREATE_STRUCTURE, hasSelection, caseName);
|
||||
checkAction(actions, EDIT_DATA_TYPE,
|
||||
pdata != null && (pdata.isStructure() || pdata.isUnion()), caseName);
|
||||
(pdata != null && (pdata.isStructure() || pdata.isUnion())) || (dt instanceof Enum),
|
||||
caseName);
|
||||
checkAction(actions, CREATE_ARRAY, true, caseName);
|
||||
checkAction(actions, DEFAULT_DATA_SETTINGS,
|
||||
(!hasSelection || isSelectionJustSingleDataInstance(sel, d)) && hasSettings, caseName);
|
||||
|
@ -0,0 +1,65 @@
|
||||
/* ###
|
||||
* 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.app.plugin.core.data;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.program.model.data.EnumDataType;
|
||||
|
||||
public class EnumDataActionTest extends AbstractDataActionTest {
|
||||
|
||||
private EnumDataType testEnum;
|
||||
private DataPlugin dataPlugin;
|
||||
private TestEnumDataAction enumDataAction;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
super.setUp();
|
||||
|
||||
testEnum = new EnumDataType("TEST_ENUM", 2);
|
||||
testEnum.add("A", 0);
|
||||
testEnum.add("B", 1);
|
||||
testEnum.add("C", 2);
|
||||
testEnum.add("D", 3);
|
||||
testEnum.add("E", 3);
|
||||
|
||||
dataPlugin = getPlugin(tool, DataPlugin.class);
|
||||
|
||||
enumDataAction = new TestEnumDataAction(dataPlugin);
|
||||
tool.addAction(enumDataAction);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllEnumDataSettings() throws Exception {
|
||||
String actionName = enumDataAction.getName();
|
||||
manipulateAllSettings(false, true, false, actionName);
|
||||
manipulateAllSettings(true, true, true, actionName);
|
||||
manipulateAllSettings(false, false, false, actionName);
|
||||
manipulateAllSettings(true, false, false, actionName);
|
||||
}
|
||||
|
||||
class TestEnumDataAction extends DataAction {
|
||||
|
||||
public TestEnumDataAction(DataPlugin plugin) {
|
||||
super(testEnum, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -44,22 +44,22 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
program = createDefaultProgram("Test", ProgramBuilder._TOY, this);
|
||||
|
||||
dataMgr = program.getDataTypeManager();
|
||||
transactionID = program.startTransaction("Test");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
program.endTransaction(transactionID, false);
|
||||
program.release(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEnum() throws Exception {
|
||||
@Test
|
||||
public void testCreateEnum() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 0);
|
||||
enumm.add("Green", 1);
|
||||
@ -88,29 +88,48 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNotNull(c.getDataType("Color"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveValue() throws Exception {
|
||||
@Test
|
||||
public void testRemoveValue() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 0);
|
||||
enumm.add("Green", 1);
|
||||
enumm.add("Blue", 2);
|
||||
enumm.add("blue", 2);
|
||||
|
||||
Category root = dataMgr.getRootCategory();
|
||||
Category c = root.createCategory("enumms");
|
||||
enumm.setCategoryPath(c.getCategoryPath());
|
||||
Enum enummDT = (Enum) dataMgr.resolve(enumm, null);
|
||||
assertEquals(3, enummDT.getCount());
|
||||
enummDT.remove("Green");
|
||||
assertEquals(2, enummDT.getCount());
|
||||
|
||||
assertArrayEquals(new long[] { 0, 1, 2 }, enumm.getValues());
|
||||
assertEquals(4, enumm.getCount());
|
||||
|
||||
enummDT.remove("Green");
|
||||
enummDT.remove("blue");
|
||||
|
||||
assertEquals(2, enummDT.getCount());
|
||||
assertArrayEquals(new long[] { 0, 2 }, enummDT.getValues());
|
||||
|
||||
assertEquals(2, enummDT.getValue("Blue"));
|
||||
try {
|
||||
enummDT.getValue("blue");
|
||||
fail("expected NoSuchElementException");
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddValue() throws Exception {
|
||||
@Test
|
||||
public void testAddValue() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 0);
|
||||
enumm.add("Green", 1);
|
||||
enumm.add("Blue", 2);
|
||||
enumm.add("blue", 2);
|
||||
|
||||
assertArrayEquals(new long[] { 0, 1, 2 }, enumm.getValues());
|
||||
assertEquals(4, enumm.getCount());
|
||||
|
||||
Category root = dataMgr.getRootCategory();
|
||||
Category c = root.createCategory("enumms");
|
||||
@ -119,12 +138,15 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
Enum enummDT = (Enum) dataMgr.resolve(enumm, null);
|
||||
|
||||
enummDT.add("Purple", 7);
|
||||
assertEquals(4, enummDT.getCount());
|
||||
assertEquals(5, enummDT.getCount());
|
||||
assertEquals(7, enummDT.getValue("Purple"));
|
||||
assertEquals(2, enummDT.getValue("Blue"));
|
||||
assertEquals(2, enummDT.getValue("blue"));
|
||||
assertArrayEquals(new long[] { 0, 1, 2, 7 }, enummDT.getValues());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditValue() throws Exception {
|
||||
@Test
|
||||
public void testEditValue() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -148,8 +170,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(2, listener.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneRetainIdentity() throws Exception {
|
||||
@Test
|
||||
public void testCloneRetainIdentity() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -168,8 +190,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertTrue(copyDT.isEquivalent(c2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyNoRetainIdentity() throws Exception {
|
||||
@Test
|
||||
public void testCopyNoRetainIdentity() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -188,8 +210,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertTrue(copyDT.isEquivalent(c2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveEnum() throws Exception {
|
||||
@Test
|
||||
public void testRemoveEnum() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -208,8 +230,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveEnum() throws Exception {
|
||||
@Test
|
||||
public void testMoveEnum() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -224,8 +246,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertNull(c.getDataType(enumm.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolve() throws Exception {
|
||||
@Test
|
||||
public void testResolve() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -239,8 +261,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(enummDT, dataMgr.getDataType(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplace() throws Exception {
|
||||
@Test
|
||||
public void testReplace() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
@ -275,8 +297,8 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEquivalent() throws Exception {
|
||||
@Test
|
||||
public void testIsEquivalent() throws Exception {
|
||||
Enum enumm = new EnumDataType("Color", 1);
|
||||
enumm.add("Red", 10);
|
||||
enumm.add("Green", 15);
|
||||
|
@ -21,6 +21,7 @@ import java.util.*;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
@ -28,9 +29,6 @@ import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.datastruct.LongObjectHashtable;
|
||||
import ghidra.util.datastruct.ObjectLongHashtable;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
|
||||
/**
|
||||
* Database implementation for the enumerated data type.
|
||||
@ -38,10 +36,13 @@ import ghidra.util.exception.NoValueException;
|
||||
*/
|
||||
class EnumDB extends DataTypeDB implements Enum {
|
||||
|
||||
private static final SettingsDefinition[] ENUM_SETTINGS_DEFINITIONS =
|
||||
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
||||
|
||||
private EnumDBAdapter adapter;
|
||||
private EnumValueDBAdapter valueAdapter;
|
||||
private ObjectLongHashtable<String> nameMap;
|
||||
private LongObjectHashtable<String> valueMap;
|
||||
private Map<String, Long> nameMap; // name to value
|
||||
private Map<Long, List<String>> valueMap; // value to names
|
||||
private List<BitGroup> bitGroups;
|
||||
|
||||
EnumDB(DataTypeManagerDB dataMgr, DBObjectCache<DataTypeDB> cache, EnumDBAdapter adapter,
|
||||
@ -49,9 +50,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
super(dataMgr, cache, record);
|
||||
this.adapter = adapter;
|
||||
this.valueAdapter = valueAdapter;
|
||||
nameMap = new ObjectLongHashtable<>();
|
||||
valueMap = new LongObjectHashtable<>();
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,71 +62,109 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return record.getString(EnumDBAdapter.ENUM_NAME_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
return ENUM_SETTINGS_DEFINITIONS;
|
||||
}
|
||||
|
||||
private void initializeIfNeeded() {
|
||||
if (nameMap != null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
initialize();
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() throws IOException {
|
||||
bitGroups = null;
|
||||
nameMap.removeAll();
|
||||
valueMap.removeAll();
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
|
||||
long[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Record rec = valueAdapter.getRecord(ids[i]);
|
||||
String valueName = rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL);
|
||||
long value = rec.getLongValue(EnumValueDBAdapter.ENUMVAL_VALUE_COL);
|
||||
nameMap.put(valueName, value);
|
||||
valueMap.put(value, valueName);
|
||||
addToCache(valueName, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#getValue(java.lang.String)
|
||||
*/
|
||||
private void addToCache(String valueName, long value) {
|
||||
nameMap.put(valueName, value);
|
||||
List<String> list = valueMap.computeIfAbsent(value, v -> new ArrayList<>());
|
||||
list.add(valueName);
|
||||
}
|
||||
|
||||
private boolean removeFromCache(String valueName) {
|
||||
Long value = nameMap.remove(valueName);
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValue(String name) throws NoSuchElementException {
|
||||
public long getValue(String valueName) throws NoSuchElementException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return nameMap.get(name);
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
throw new NoSuchElementException(name + " does not exist in this enum");
|
||||
initializeIfNeeded();
|
||||
Long value = nameMap.get(valueName);
|
||||
if (value == null) {
|
||||
throw new NoSuchElementException("No value for " + valueName);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#getName(long)
|
||||
*/
|
||||
@Override
|
||||
public String getName(long value) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return valueMap.get(value);
|
||||
initializeIfNeeded();
|
||||
List<String> list = valueMap.get(value);
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return list.get(0);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#isDynamicallySized()
|
||||
*/
|
||||
@Override
|
||||
public boolean isDynamicallySized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#getValues()
|
||||
*/
|
||||
@Override
|
||||
public long[] getValues() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
long[] values = valueMap.getKeys();
|
||||
initializeIfNeeded();
|
||||
long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray();
|
||||
Arrays.sort(values);
|
||||
return values;
|
||||
}
|
||||
@ -137,31 +173,25 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#getNames()
|
||||
*/
|
||||
@Override
|
||||
public String[] getNames() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
String[] names = nameMap.getKeys(new String[nameMap.size()]);
|
||||
Arrays.sort(names);
|
||||
return names;
|
||||
initializeIfNeeded();
|
||||
return nameMap.keySet().toArray(new String[nameMap.size()]);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#getCount()
|
||||
*/
|
||||
@Override
|
||||
public int getCount() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
initializeIfNeeded();
|
||||
return nameMap.size();
|
||||
}
|
||||
finally {
|
||||
@ -169,58 +199,62 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#add(java.lang.String, long)
|
||||
*/
|
||||
@Override
|
||||
public void add(String name, long value) {
|
||||
public void add(String valueName, long value) {
|
||||
lock.acquire();
|
||||
bitGroups = null;
|
||||
try {
|
||||
checkDeleted();
|
||||
if (nameMap.contains(name)) {
|
||||
throw new IllegalArgumentException(name + " already exists in this enum");
|
||||
}
|
||||
try {
|
||||
valueAdapter.createRecord(key, name, value);
|
||||
nameMap.put(name, value);
|
||||
if (!valueMap.contains(value)) {
|
||||
valueMap.put(value, name);
|
||||
}
|
||||
adapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
checkValue(value);
|
||||
initializeIfNeeded();
|
||||
if (nameMap.containsKey(valueName)) {
|
||||
throw new IllegalArgumentException(valueName + " already exists in this enum");
|
||||
}
|
||||
bitGroups = null;
|
||||
valueAdapter.createRecord(key, valueName, value);
|
||||
adapter.updateRecord(record, true);
|
||||
addToCache(valueName, value);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#remove(java.lang.String)
|
||||
*/
|
||||
private void checkValue(long value) {
|
||||
int length = getLength();
|
||||
if (length == 8) {
|
||||
return; // all long values permitted
|
||||
}
|
||||
// compute maximum enum value as a positive value: (2^length)-1
|
||||
long max = (1L << (getLength() * 8)) - 1;
|
||||
if (value > max) {
|
||||
throw new IllegalArgumentException(
|
||||
getName() + " enum value 0x" + Long.toHexString(value) +
|
||||
" is outside the range of 0x0 to 0x" + Long.toHexString(max));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String name) {
|
||||
public void remove(String valueName) {
|
||||
lock.acquire();
|
||||
bitGroups = null;
|
||||
try {
|
||||
checkDeleted();
|
||||
if (!nameMap.contains(name)) {
|
||||
initializeIfNeeded();
|
||||
if (!removeFromCache(valueName)) {
|
||||
return;
|
||||
}
|
||||
long value = nameMap.get(name);
|
||||
nameMap.remove(name);
|
||||
if (name.equals(valueMap.get(value))) {
|
||||
valueMap.remove(value);
|
||||
}
|
||||
bitGroups = null;
|
||||
|
||||
long[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Record rec = valueAdapter.getRecord(ids[i]);
|
||||
if (name.equals(rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL))) {
|
||||
if (valueName.equals(rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL))) {
|
||||
valueAdapter.removeRecord(ids[i]);
|
||||
break;
|
||||
}
|
||||
@ -231,17 +265,11 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// can't happen
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see ghidra.program.model.data.Enum#replace(ghidra.program.model.data.Enum)
|
||||
*/
|
||||
@Override
|
||||
public void replaceWith(DataType dataType) {
|
||||
if (!(dataType instanceof Enum)) {
|
||||
@ -249,30 +277,33 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
Enum enumm = (Enum) dataType;
|
||||
lock.acquire();
|
||||
bitGroups = null;
|
||||
try {
|
||||
checkDeleted();
|
||||
int oldLength = getLength();
|
||||
nameMap.removeAll();
|
||||
valueMap.removeAll();
|
||||
|
||||
bitGroups = null;
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
|
||||
long[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
valueAdapter.removeRecord(ids[i]);
|
||||
}
|
||||
String[] names = enumm.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (nameMap.contains(names[i])) {
|
||||
throw new IllegalArgumentException(names[i] + " already exists in this Enum");
|
||||
}
|
||||
long value = enumm.getValue(names[i]);
|
||||
valueAdapter.createRecord(key, names[i], value);
|
||||
nameMap.put(names[i], value);
|
||||
valueMap.put(value, names[i]);
|
||||
|
||||
int oldLength = getLength();
|
||||
int newLength = enumm.getLength();
|
||||
|
||||
if (oldLength != newLength) {
|
||||
record.setByteValue(EnumDBAdapter.ENUM_SIZE_COL, (byte) newLength);
|
||||
adapter.updateRecord(record, true);
|
||||
}
|
||||
|
||||
int newLength = enumm.getLength();
|
||||
record.setByteValue(EnumDBAdapter.ENUM_SIZE_COL, (byte) newLength);
|
||||
adapter.updateRecord(record, true);
|
||||
String[] names = enumm.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
long value = enumm.getValue(names[i]);
|
||||
valueAdapter.createRecord(key, names[i], value);
|
||||
adapter.updateRecord(record, true);
|
||||
addToCache(names[i], value);
|
||||
}
|
||||
|
||||
if (oldLength != newLength) {
|
||||
notifySizeChanged();
|
||||
@ -308,9 +339,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return enumDataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getMnemonic(ghidra.docking.settings.Settings)
|
||||
*/
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
lock.acquire();
|
||||
@ -323,9 +351,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getLength()
|
||||
*/
|
||||
@Override
|
||||
public int getLength() {
|
||||
lock.acquire();
|
||||
@ -338,9 +363,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public String getDescription() {
|
||||
lock.acquire();
|
||||
@ -354,9 +376,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Enum#setDescription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
lock.acquire();
|
||||
@ -374,9 +393,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
lock.acquire();
|
||||
@ -412,9 +428,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return Scalar.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getRepresentation(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
lock.acquire();
|
||||
@ -501,9 +514,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return valueName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#isEquivalent(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dt) {
|
||||
if (dt == this) {
|
||||
@ -513,7 +523,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkIsValid();
|
||||
Enum enumm = (Enum) dt;
|
||||
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), enumm.getName()) ||
|
||||
getLength() != enumm.getLength() || getCount() != enumm.getCount()) {
|
||||
@ -536,16 +545,15 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.database.DatabaseObject#refresh()
|
||||
*/
|
||||
@Override
|
||||
protected boolean refresh() {
|
||||
try {
|
||||
nameMap = null;
|
||||
valueMap = null;
|
||||
bitGroups = null;
|
||||
Record rec = adapter.getRecord(key);
|
||||
if (rec != null) {
|
||||
record = rec;
|
||||
initialize();
|
||||
return super.refresh();
|
||||
}
|
||||
}
|
||||
@ -555,9 +563,6 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeReplaced(ghidra.program.model.data.DataType, ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
||||
// not applicable
|
||||
@ -575,17 +580,11 @@ class EnumDB extends DataTypeDB implements Enum {
|
||||
adapter.updateRecord(record, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeDeleted(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeNameChanged(ghidra.program.model.data.DataType, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
// not applicable
|
||||
|
@ -33,9 +33,11 @@ import ghidra.util.exception.DuplicateNameException;
|
||||
*/
|
||||
class PointerDB extends DataTypeDB implements Pointer {
|
||||
|
||||
private static final SettingsDefinition[] POINTER_SETTINGS_DEFINITIONS =
|
||||
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
||||
|
||||
private PointerDBAdapter adapter;
|
||||
private String displayName;
|
||||
private SettingsDefinition[] settingsDef;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -74,9 +76,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
return pointerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Pointer#getDataType()
|
||||
*/
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
lock.acquire();
|
||||
@ -91,18 +90,7 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (settingsDef == null) {
|
||||
DataType dt = newPointer(getDataType());
|
||||
settingsDef = dt.getSettingsDefinitions();
|
||||
}
|
||||
return settingsDef;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return POINTER_SETTINGS_DEFINITIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,9 +114,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#clone(ghidra.program.model.data.DataTypeManager)
|
||||
*/
|
||||
@Override
|
||||
public final DataType clone(DataTypeManager dtm) {
|
||||
if (dtm == getDataTypeManager()) {
|
||||
@ -143,9 +128,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
return clone(dtm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
validate(lock);
|
||||
@ -166,9 +148,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
return localDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getMnemonic(ghidra.docking.settings.Settings)
|
||||
*/
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
lock.acquire();
|
||||
@ -185,9 +164,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Pointer#isDynamicallySized()
|
||||
*/
|
||||
@Override
|
||||
public boolean isDynamicallySized() {
|
||||
lock.acquire();
|
||||
@ -200,9 +176,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getLength()
|
||||
*/
|
||||
@Override
|
||||
public int getLength() {
|
||||
lock.acquire();
|
||||
@ -219,9 +192,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public String getDescription() {
|
||||
lock.acquire();
|
||||
@ -250,9 +220,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
lock.acquire();
|
||||
@ -278,9 +245,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
return Address.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getRepresentation(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
lock.acquire();
|
||||
@ -298,9 +262,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#isEquivalent(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dt) {
|
||||
if (dt == null) {
|
||||
@ -339,9 +300,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
otherDataType.getPathName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeReplaced(ghidra.program.model.data.DataType, ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
||||
if (newDt == this) {
|
||||
@ -371,9 +329,6 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeDeleted(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
if (getDataType() == dt) {
|
||||
@ -440,26 +395,17 @@ class PointerDB extends DataTypeDB implements Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#setCategoryPath(ghidra.program.model.data.CategoryPath)
|
||||
*/
|
||||
@Override
|
||||
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
|
||||
// not permitted to move - follows base type (see updatePath)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dependsOn(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public boolean dependsOn(DataType dt) {
|
||||
DataType myDt = getDataType();
|
||||
return (myDt != null && (myDt == dt || myDt.dependsOn(dt)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Pointer#newPointer(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public Pointer newPointer(DataType dataType) {
|
||||
if (isDynamicallySized()) {
|
||||
|
@ -32,7 +32,7 @@ import ghidra.util.exception.DuplicateNameException;
|
||||
*/
|
||||
public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
|
||||
|
||||
private static SettingsDefinition[] STANDARD_SETTINGS_DEFINITIONS =
|
||||
private static final SettingsDefinition[] STANDARD_SETTINGS_DEFINITIONS =
|
||||
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
||||
|
||||
private SettingsDefinition[] settingDefs;
|
||||
|
@ -20,17 +20,20 @@ import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.datastruct.LongObjectHashtable;
|
||||
import ghidra.util.datastruct.ObjectLongHashtable;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
|
||||
public class EnumDataType extends GenericDataType implements Enum {
|
||||
private ObjectLongHashtable<String> defs;
|
||||
|
||||
private static final SettingsDefinition[] ENUM_SETTINGS_DEFINITIONS =
|
||||
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
|
||||
|
||||
private Map<String, Long> nameMap; // name to value
|
||||
private Map<Long, List<String>> valueMap; // value to names
|
||||
private int length;
|
||||
private String description;
|
||||
private List<BitGroup> bitGroups;
|
||||
@ -45,7 +48,11 @@ public class EnumDataType extends GenericDataType implements Enum {
|
||||
|
||||
public EnumDataType(CategoryPath path, String name, int length, DataTypeManager dtm) {
|
||||
super(path, name, dtm);
|
||||
defs = new ObjectLongHashtable<>();
|
||||
if (length < 1 || length > 8) {
|
||||
throw new IllegalArgumentException("unsupported enum length: " + length);
|
||||
}
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@ -54,13 +61,19 @@ public class EnumDataType extends GenericDataType implements Enum {
|
||||
DataTypeManager dtm) {
|
||||
super(path, name, universalID, sourceArchive, lastChangeTime, lastChangeTimeInSourceArchive,
|
||||
dtm);
|
||||
defs = new ObjectLongHashtable<>();
|
||||
if (length < 1 || length > 8) {
|
||||
throw new IllegalArgumentException("unsupported enum length: " + length);
|
||||
}
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#isDynamicallySized()
|
||||
*/
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
return ENUM_SETTINGS_DEFINITIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamicallySized() {
|
||||
return false;
|
||||
@ -68,91 +81,96 @@ public class EnumDataType extends GenericDataType implements Enum {
|
||||
|
||||
@Override
|
||||
public long getValue(String valueName) throws NoSuchElementException {
|
||||
try {
|
||||
return defs.get(valueName);
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
Long value = nameMap.get(valueName);
|
||||
if (value == null) {
|
||||
throw new NoSuchElementException("No value for " + valueName);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(long value) {
|
||||
String[] names = defs.getKeys(new String[defs.size()]);
|
||||
for (String name1 : names) {
|
||||
try {
|
||||
long nameValue = defs.get(name1);
|
||||
if (nameValue == value) {
|
||||
return name1;
|
||||
}
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// can't happen
|
||||
}
|
||||
List<String> list = valueMap.get(value);
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getValues() {
|
||||
String[] names = defs.getKeys(new String[defs.size()]);
|
||||
LongObjectHashtable<String> keyTable = new LongObjectHashtable<>();
|
||||
for (String name1 : names) {
|
||||
try {
|
||||
long value = defs.get(name1);
|
||||
keyTable.put(value, name1);
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// can't happen
|
||||
}
|
||||
}
|
||||
long[] values = keyTable.getKeys();
|
||||
long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray();
|
||||
Arrays.sort(values);
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getNames() {
|
||||
String[] names = defs.getKeys(new String[defs.size()]);
|
||||
Arrays.sort(names);
|
||||
return names;
|
||||
return nameMap.keySet().toArray(new String[nameMap.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return defs.size();
|
||||
return nameMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(String valueName, long value) {
|
||||
bitGroups = null;
|
||||
checkValue(value);
|
||||
if (defs.contains(valueName)) {
|
||||
try {
|
||||
if (defs.get(valueName) == value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
}
|
||||
throw new IllegalArgumentException(name + " enum value " + value + " already assigned");
|
||||
if (nameMap.containsKey(valueName)) {
|
||||
throw new IllegalArgumentException(name + " already exists in this enum");
|
||||
}
|
||||
defs.put(valueName, value);
|
||||
nameMap.put(valueName, value);
|
||||
List<String> list = valueMap.get(value);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
valueMap.put(value, list);
|
||||
}
|
||||
list.add(valueName);
|
||||
}
|
||||
|
||||
private void checkValue(long value) {
|
||||
long max = (1L << (length * 8)) - 1;
|
||||
if (max > 0 && value > max) {
|
||||
throw new IllegalArgumentException(name + " enum value 0x" + Long.toHexString(value) +
|
||||
" is outside the range of 0x0 to 0x" + Long.toHexString(max));
|
||||
if (length == 8) {
|
||||
return; // all long values permitted
|
||||
}
|
||||
// compute maximum enum value as a positive value: (2^length)-1
|
||||
long max = (1L << (getLength() * 8)) - 1;
|
||||
if (value > max) {
|
||||
throw new IllegalArgumentException(
|
||||
getName() + " enum value 0x" + Long.toHexString(value) +
|
||||
" is outside the range of 0x0 to 0x" + Long.toHexString(max));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTooBig(int testLength, long value) {
|
||||
if (length == 8) {
|
||||
return false; // all long values permitted
|
||||
}
|
||||
// compute maximum enum value as a positive value: (2^length)-1
|
||||
long max = (1L << (testLength * 8)) - 1;
|
||||
return value > max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String valueName) {
|
||||
bitGroups = null;
|
||||
defs.remove(valueName);
|
||||
Long value = nameMap.get(valueName);
|
||||
if (value != null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -200,14 +218,6 @@ public class EnumDataType extends GenericDataType implements Enum {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
private boolean isTooBig(int testLength, long value) {
|
||||
long max = (1L << (testLength * 8)) - 1;
|
||||
if (max > 0 && value > max) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description == null ? "" : description;
|
||||
@ -368,46 +378,36 @@ public class EnumDataType extends GenericDataType implements Enum {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
Enum enumm = (Enum) dataType;
|
||||
defs.removeAll();
|
||||
nameMap = new HashMap<>();
|
||||
valueMap = new HashMap<>();
|
||||
setLength(enumm.getLength());
|
||||
String[] names = enumm.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
defs.put(names[i], enumm.getValue(names[i]));
|
||||
add(names[i], enumm.getValue(names[i]));
|
||||
}
|
||||
stateChanged(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeSizeChanged(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeSizeChanged(DataType dt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeDeleted(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeNameChanged(ghidra.program.model.data.DataType, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dataTypeReplaced(ghidra.program.model.data.DataType, ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dependsOn(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public boolean dependsOn(DataType dt) {
|
||||
return false;
|
||||
|
@ -17,15 +17,12 @@ package ghidra.program.model.data;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.ByteMemBufferImpl;
|
||||
import ghidra.util.BigEndianDataConverter;
|
||||
import ghidra.util.UniversalIdGenerator;
|
||||
import mockit.Expectations;
|
||||
import mockit.Mocked;
|
||||
|
||||
public class EnumDataTypeTest {
|
||||
@Mocked
|
||||
MemBuffer memBuffer;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@ -33,33 +30,27 @@ public class EnumDataTypeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegativeValue() throws MemoryAccessException {
|
||||
new Expectations() {
|
||||
{
|
||||
memBuffer.getInt(anyInt);
|
||||
result = 0xffffffff;
|
||||
}
|
||||
};
|
||||
public void testNegativeValue() {
|
||||
|
||||
EnumDataType enumDt = new EnumDataType("Test", 4);
|
||||
enumDt.add("bob", 0xffffffffL);
|
||||
|
||||
ByteMemBufferImpl memBuffer = new ByteMemBufferImpl(Address.NO_ADDRESS,
|
||||
BigEndianDataConverter.INSTANCE.getBytes(-1), true);
|
||||
|
||||
Assert.assertEquals("bob", enumDt.getRepresentation(memBuffer, null, 0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpperBitLongValue() throws MemoryAccessException {
|
||||
new Expectations() {
|
||||
{
|
||||
memBuffer.getInt(anyInt);
|
||||
result = 0x80000000;
|
||||
}
|
||||
};
|
||||
public void testUpperBitLongValue() {
|
||||
|
||||
EnumDataType enumDt = new EnumDataType("Test", 4);
|
||||
enumDt.add("bob", 0x80000000L);
|
||||
|
||||
ByteMemBufferImpl memBuffer = new ByteMemBufferImpl(Address.NO_ADDRESS,
|
||||
BigEndianDataConverter.INSTANCE.getBytes(Integer.MIN_VALUE), true);
|
||||
|
||||
Assert.assertEquals("bob", enumDt.getRepresentation(memBuffer, null, 0));
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user