diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java index 22e78635b2..b7ee1f6194 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java @@ -4,9 +4,9 @@ * 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. @@ -23,6 +23,7 @@ import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.GhidraOptions; import ghidra.app.plugin.core.hover.AbstractConfigurableHover; import ghidra.app.util.ToolTipUtils; +import ghidra.app.util.viewer.field.ResourceFieldLocation; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; @@ -126,6 +127,11 @@ public class DataTypeListingHover extends AbstractConfigurableHover implements L (EquateOperandFieldLocation) programLocation; return createEquateToolTipComponent(program, equateLocation.getEquate()); } + if (programLocation instanceof ResourceFieldLocation resourceLoc) { + Data data = resourceLoc.getResourceData(); + dt = data.getDataType(); + return createTooltipComponent(dt.getRepresentation(data, data, data.getLength())); + } return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java index d35bcf7038..edde1b3ab4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java @@ -20,12 +20,20 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.List; +import javax.swing.Icon; import javax.swing.event.ChangeListener; -import docking.widgets.fieldpanel.field.*; -import docking.widgets.fieldpanel.support.*; +import docking.widgets.fieldpanel.field.AbstractTextFieldElement; +import docking.widgets.fieldpanel.field.AttributedString; +import docking.widgets.fieldpanel.field.CompositeFieldElement; +import docking.widgets.fieldpanel.field.FieldElement; +import docking.widgets.fieldpanel.support.FieldLocation; +import docking.widgets.fieldpanel.support.FieldUtils; +import docking.widgets.fieldpanel.support.RowColLocation; import ghidra.GhidraOptions; -import ghidra.app.util.*; +import ghidra.app.util.ColorAndStyle; +import ghidra.app.util.ListingHighlightProvider; +import ghidra.app.util.SymbolInspector; import ghidra.app.util.viewer.field.ListingColors.FunctionColors; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -33,13 +41,30 @@ import ghidra.app.util.viewer.proxy.ProxyObj; import ghidra.framework.options.Options; import ghidra.framework.options.ToolOptions; import ghidra.program.model.address.Address; -import ghidra.program.model.data.*; +import ghidra.program.model.data.DataImage; +import ghidra.program.model.data.DataType; import ghidra.program.model.data.Enum; +import ghidra.program.model.data.Playable; +import ghidra.program.model.data.Union; import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.*; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.Data; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.LabelString; +import ghidra.program.model.listing.OperandRepresentationList; +import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.Variable; +import ghidra.program.model.listing.VariableOffset; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.symbol.*; -import ghidra.program.util.*; +import ghidra.program.model.symbol.Equate; +import ghidra.program.model.symbol.EquateTable; +import ghidra.program.model.symbol.Reference; +import ghidra.program.model.symbol.ReferenceManager; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolTable; +import ghidra.program.util.EquateOperandFieldLocation; +import ghidra.program.util.OperandFieldLocation; +import ghidra.program.util.ProgramLocation; import ghidra.util.HelpLocation; /** @@ -180,8 +205,8 @@ abstract class OperandFieldHelper extends FieldFactory { this.maxDisplayLines = maxLines; } - FieldLocation getFieldLocation(BigInteger index, int fieldNum, ListingField field, - int opIndex, int column) { + FieldLocation getFieldLocation(BigInteger index, int fieldNum, ListingField field, int opIndex, + int column) { if (field instanceof ListingTextField listingField) { RowColLocation rcl = listingField.dataToScreenLocation(opIndex, column); return new FieldLocation(index, fieldNum, rcl.row(), rcl.col()); @@ -211,7 +236,8 @@ abstract class OperandFieldHelper extends FieldFactory { if (lf instanceof ImageFactoryField) { Data data = (Data) obj; - if (data.getValue() instanceof DataImage) { + Object value = data.getValue(); + if (value instanceof DataImage || value instanceof Icon) { return new ResourceFieldLocation(data.getProgram(), data.getMinAddress(), data.getComponentPath(), codeUnitFormat.getDataValueRepresentationString(data), 0, col, data); @@ -362,6 +388,10 @@ abstract class OperandFieldHelper extends FieldFactory { return new ImageFactoryField(this, ((DataImage) value).getImageIcon(), proxy, getMetrics(), startX + varWidth, width); } + if (value instanceof Icon) { + return new ImageFactoryField(this, (Icon) value, proxy, getMetrics(), startX + varWidth, + width); + } else if (value instanceof Playable) { return new ImageFactoryField(this, ((Playable) value).getImageIcon(), proxy, getMetrics(), startX + varWidth, width); @@ -452,8 +482,8 @@ abstract class OperandFieldHelper extends FieldFactory { if (wrapOnSemicolon) { List lines = breakIntoLines(elements); if (lines.size() == 1) { - return ListingTextField.createSingleLineTextField(this, proxy, - lines.get(0), startX + varWidth, width, hlProvider); + return ListingTextField.createSingleLineTextField(this, proxy, lines.get(0), + startX + varWidth, width, hlProvider); } return ListingTextField.createMultilineTextField(this, proxy, lines, startX, width, hlProvider); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java index 19bf6a3013..de294807f8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FormatManager.java @@ -28,8 +28,10 @@ import ghidra.app.util.viewer.field.*; import ghidra.framework.options.*; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; -import ghidra.program.model.data.*; +import ghidra.program.model.data.Array; +import ghidra.program.model.data.DataType; import ghidra.program.model.listing.*; +import ghidra.program.model.scalar.Scalar; import ghidra.util.classfinder.*; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; @@ -259,8 +261,7 @@ public class FormatManager implements OptionsChangeListener { return false; } DataType type = data.getBaseDataType(); - return type.getLength() > 0 && type instanceof AbstractIntegerDataType || - type instanceof DefaultDataType; + return type.getLength() > 0 && type.getValueClass(null) == Scalar.class; } /** @@ -944,8 +945,7 @@ public class FormatManager implements OptionsChangeListener { private class MultipleHighlighterProvider implements ListingHighlightProvider { - private List highlightProviders = - new CopyOnWriteArrayList<>(); + private List highlightProviders = new CopyOnWriteArrayList<>(); @Override public Highlight[] createHighlights(String text, ListingField field, int cursorTextOffset) { @@ -961,8 +961,7 @@ public class FormatManager implements OptionsChangeListener { int size = highlightProviders.size(); for (int i = size - 1; i >= 0; i--) { ListingHighlightProvider provider = highlightProviders.get(i); - Highlight[] highlights = - provider.createHighlights(text, field, cursorTextOffset); + Highlight[] highlights = provider.createHighlights(text, field, cursorTextOffset); for (Highlight highlight : highlights) { list.add(highlight); } diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java index 0f2b45ec86..033a2244ae 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsDefinition.java @@ -4,9 +4,9 @@ * 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. @@ -16,7 +16,6 @@ package ghidra.docking.settings; import java.util.ArrayList; -import java.util.Arrays; import java.util.function.Predicate; /** @@ -40,14 +39,10 @@ public interface SettingsDefinition { if (settings == null) { return additional; } - ArrayList list = new ArrayList<>(); - list.addAll(Arrays.asList(settings)); - for (SettingsDefinition def : additional) { - if (!list.contains(def)) { - list.add(def); - } - } - return list.toArray(new SettingsDefinition[list.size()]); + SettingsDefinition[] newArray = new SettingsDefinition[settings.length + additional.length]; + System.arraycopy(settings, 0, newArray, 0, settings.length); + System.arraycopy(additional, 0, newArray, settings.length, additional.length); + return newArray; } /** diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractColorDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractColorDataType.java new file mode 100644 index 0000000000..57e03d31bc --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractColorDataType.java @@ -0,0 +1,145 @@ +/* ### + * 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.model.data; + +import java.awt.Color; +import java.math.BigInteger; +import java.util.List; + +import ghidra.docking.settings.Settings; +import ghidra.docking.settings.SettingsImpl; +import ghidra.program.model.listing.Data; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.scalar.Scalar; +import ghidra.util.DataConverter; +import ghidra.util.Msg; + +/** + * {@link AbstractColorDataType} provides an abstract color datatype whose value corresponds to an + * approriate Color decode of the bytes at a memory location. This datatype is a fixed-length + * unsigned integer type which is rendered with a Color block when applied as {@link Data}. + *

+ * The {@link #getValue(MemBuffer, Settings, int)} method returns {@link ColorIcon} instance. + *

+ * A fixed-length RGB datatype will adopt a predefined default encoding, however a Typedef may + * be formed from the RGB datatype which will allow an alternative encoding to be specified + * via a default Setting (See {@link #getTypeDefSettingsDefinitions()}). + */ +public abstract class AbstractColorDataType extends AbstractUnsignedIntegerDataType { + + private static Settings rgbValueSettings = new SettingsImpl(); + static { + PADDING.setPadded(rgbValueSettings, true); + } + + /** + * Abstract color datatype whose value corresponds to an approriate Color decode + * of the bytes at a memory location. + * @param name datatype name + * @param dtm datatype manager + */ + public AbstractColorDataType(String name, DataTypeManager dtm) { + super(name, dtm); + } + + @Override + public AbstractIntegerDataType getOppositeSignednessDataType() { + Msg.error(this, "Unsupported method use for " + getClass().getName(), + new UnsupportedOperationException()); + return this; + } + + @Override + public final Class getValueClass(Settings settings) { + return ColorIcon.class; + } + + @Override + public final String getRepresentation(MemBuffer buf, Settings settings, int length) { + + int size = getLength(); + byte[] bytes = new byte[size]; + if (buf.getBytes(bytes, 0) != size) { + return "??"; + } + + // Full RGB value always displayed as Padded Hex but must respect Endianess setting + BigInteger value = DataConverter.getInstance(ENDIAN.isBigEndian(settings, buf)) + .getBigInteger(bytes, size, true); + String valueRep = getRepresentation(value, rgbValueSettings, 8 * size, false); + + // Representation: : {} + StringBuilder strbuf = new StringBuilder(); + strbuf.append(getEncodingName(settings)); + strbuf.append(" "); + strbuf.append(valueRep); + strbuf.append(" {"); + int cnt = 0; + for (ComponentValue compValue : getComponentValues(buf, settings)) { + if (cnt++ != 0) { + strbuf.append(","); + } + strbuf.append(compValue.getRepresentation(settings)); + } + strbuf.append("}"); + return strbuf.toString(); + } + + protected abstract String getEncodingName(Settings settings); + + protected abstract List getComponentValues(MemBuffer buf, Settings settings); + + @Override + public ColorIcon getValue(MemBuffer buf, Settings settings, int length) { + int size = getLength(); + if (size < 1 || size > 8) { + throw new AssertionError("Unsupported length: " + size); + } + byte[] bytes = new byte[size]; + if (buf.getBytes(bytes, 0) != size) { + return null; // insufficient bytes available + } + return new ColorIcon(decodeColor(buf, settings)); + } + + /** + * Generate the {@link Color} which corresponds to the memory bytes. + * Implementation must factor Endianess setting into value used. + * @param buf memory bytes buffer + * @param settings datatype settings + * @return Color to be rendered + */ + protected abstract Color decodeColor(MemBuffer buf, Settings settings); + + protected record ComponentValue(String name, int value, int bitLength) { + String getRepresentation(Settings settings) { + + BigInteger bigValue = BigInteger.valueOf(Integer.toUnsignedLong(value)); + + // CHAR format will default to HEX format + return name + ":" + + AbstractIntegerDataType.getRepresentation(bigValue, settings, bitLength, false); + } + } + + protected static int getFieldValue(long fullValue, int rightShift, int finalMask) { + return (int) (fullValue >>> rightShift) & finalMask; + } + + protected static int scaleFieldValue(int value, int bitSize) { + return (value * 255) / ((1 << bitSize) - 1); + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java index cb6d4a95bd..637465df94 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractDataType.java @@ -28,7 +28,7 @@ import ghidra.util.UniversalID; */ public abstract class AbstractDataType implements DataType { - private final static TypeDefSettingsDefinition[] EMPTY_TYPEDEF_DEFINITIONS = + protected final static TypeDefSettingsDefinition[] EMPTY_TYPEDEF_DEFINITIONS = new TypeDefSettingsDefinition[0]; protected String name; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java index 3e17923920..982011fb10 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AbstractIntegerDataType.java @@ -4,9 +4,9 @@ * 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. @@ -53,9 +53,12 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt protected static final DataTypeMnemonicSettingsDefinition MNEMONIC = DataTypeMnemonicSettingsDefinition.DEF; - private static SettingsDefinition[] SETTINGS_DEFS = + protected static final SettingsDefinition[] SETTINGS_DEFS = { FormatSettingsDefinition.DEF_HEX, PADDING, ENDIAN, MNEMONIC }; + protected static final TypeDefSettingsDefinition[] TYPEDEF_SETTINGS_DEFS = + EMPTY_TYPEDEF_DEFINITIONS; + /** * Constructor * @@ -81,6 +84,11 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt return SETTINGS_DEFS; } + @Override + public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() { + return TYPEDEF_SETTINGS_DEFS; + } + /** * Determine if this type is signed. * @return true if this is a signed integer data-type @@ -243,9 +251,8 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt this); } BigInteger maxValueExclusive = BigInteger.ONE.shiftLeft(length * 8 - (isSigned() ? 1 : 0)); - BigInteger minValueInclusive = isSigned() - ? BigInteger.ONE.shiftLeft(length * 8 - 1).negate() - : BigInteger.ZERO; + BigInteger minValueInclusive = + isSigned() ? BigInteger.ONE.shiftLeft(length * 8 - 1).negate() : BigInteger.ZERO; if (bigValue.compareTo(maxValueExclusive) >= 0) { throw new DataTypeEncodeException("Value is too large", bigValue, this); } @@ -282,11 +289,12 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt BigInteger value = DataConverter.getInstance(ENDIAN.isBigEndian(settings, buf)) .getBigInteger(bytes, size, true); - if (getFormatSettingsDefinition().getFormat(settings) == FormatSettingsDefinition.CHAR) { + int format = getFormatSettingsDefinition().getFormat(settings); + if (format == FormatSettingsDefinition.CHAR) { return StringDataInstance.getCharRepresentation(this, bytes, settings); } - return getRepresentation(value, settings, 8 * length); + return getRepresentation(value, settings, 8 * length, isSigned()); } /** @@ -298,16 +306,18 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt * @param bigInt BigInteger value with the appropriate sign * @param settings integer format settings (PADDING, FORMAT, etc.) * @param bitLength number of value bits to be used from bigInt + * @param isSigned true if type is signed, else false * @return formatted integer string */ - /*package*/ String getRepresentation(BigInteger bigInt, Settings settings, int bitLength) { + /*package*/ static String getRepresentation(BigInteger bigInt, Settings settings, int bitLength, + boolean isSigned) { - int format = getFormatSettingsDefinition().getFormat(settings); boolean padded = PADDING.isPadded(settings); boolean negative = bigInt.signum() < 0; - if (negative && (!isSigned() || (format != FormatSettingsDefinition.DECIMAL))) { + int format = FormatSettingsDefinition.DEF_HEX.getChoice(settings); + if (negative && (!isSigned || (format != FormatSettingsDefinition.DECIMAL))) { // force use of unsigned value bigInt = bigInt.add(BigInteger.valueOf(2).pow(bitLength)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java index 3ad429f36c..bcccdca19e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java @@ -102,8 +102,8 @@ public class BitFieldDataType extends AbstractDataType { /** * Get the effective bit-size based upon the specified base type size. A bit size * larger than the base type size will truncated to the base type size. - * @param declaredBitSize - * @param baseTypeByteSize + * @param declaredBitSize declare bitfield size + * @param baseTypeByteSize base datatype size in bytes * @return effective bit-size */ public static int getEffectiveBitSize(int declaredBitSize, int baseTypeByteSize) { @@ -417,9 +417,13 @@ public class BitFieldDataType extends AbstractDataType { if (dt instanceof Enum) { return ((Enum) dt).getRepresentation(big, settings, effectiveBitSize); } + if (dt instanceof BooleanDataType) { + // TRUE or FALSE representation + return ((BooleanDataType) dt).getRepresentation(big, settings, effectiveBitSize); + } AbstractIntegerDataType intDT = (AbstractIntegerDataType) dt; - if (intDT.getFormatSettingsDefinition() - .getFormat(settings) == FormatSettingsDefinition.CHAR) { + int format = intDT.getFormatSettingsDefinition().getFormat(settings); + if (format == FormatSettingsDefinition.CHAR) { if (big.signum() < 0) { big = big.add(BigInteger.valueOf(2).pow(effectiveBitSize)); } @@ -429,7 +433,7 @@ public class BitFieldDataType extends AbstractDataType { return StringDataInstance.getCharRepresentation(this, bytes, settings); } - return intDT.getRepresentation(big, settings, effectiveBitSize); + return AbstractIntegerDataType.getRepresentation(big, settings, effectiveBitSize, isSigned); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java index 48ba33918a..b018efea7d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BooleanDataType.java @@ -4,9 +4,9 @@ * 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. @@ -28,7 +28,7 @@ import ghidra.program.model.mem.MemoryAccessException; */ public class BooleanDataType extends AbstractUnsignedIntegerDataType { - private static SettingsDefinition[] SETTINGS_DEFS = {}; + private static SettingsDefinition[] BOOLEAN_SETTINGS_DEFS = {}; public static final BooleanDataType dataType = new BooleanDataType(); @@ -95,14 +95,13 @@ public class BooleanDataType extends AbstractUnsignedIntegerDataType { return b.booleanValue() ? "TRUE" : "FALSE"; } - @Override public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength) { return BigInteger.ZERO.equals(bigInt) ? "FALSE" : "TRUE"; } @Override protected SettingsDefinition[] getBuiltInSettingsDefinitions() { - return SETTINGS_DEFS; + return BOOLEAN_SETTINGS_DEFS; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ColorIcon.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ColorIcon.java new file mode 100644 index 0000000000..f2839fda81 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ColorIcon.java @@ -0,0 +1,88 @@ +/* ### + * 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.model.data; + +import java.awt.*; + +import javax.swing.Icon; + +import generic.theme.GColor; + +/** + * {@link ColorIcon} provides a color icon patch to convey a specified color with + * Alpha transparancy. This implementation was created in support of color + * data types (see {@link AbstractColorDataType}). + */ +public class ColorIcon implements Icon { + + private static final int WIDTH = 16; + private static final int HEIGHT = 16; + + private static Color BORDER_COLOR = new GColor("color.fg"); + + private final Color color; + + /** + * Construct a 16x16 RGB color icon patch + * @param color icon color + */ + ColorIcon(Color color) { + this.color = color; + } + + @Override + public int getIconHeight() { + return HEIGHT; + } + + @Override + public int getIconWidth() { + return WIDTH; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + + Graphics2D g2d = (Graphics2D) g; + + // Enable anti-aliasing + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // Draw a white box with a diagonal black line under the colored-box to convey + // Alpha channel transparency while preserving color. + g.setColor(Color.WHITE); + g.fillRect(x + 1, y + 1, WIDTH - 2, HEIGHT - 2); + g.setColor(Color.BLACK); + g.drawLine(x + 1, y + 1, x + WIDTH - 2, y + HEIGHT - 2); + + // Draw colored-box + g.setColor(color); + g.fillRect(x + 1, y + 1, WIDTH - 2, HEIGHT - 2); + g.setColor(BORDER_COLOR); + g.drawLine(x + 1, y, x + WIDTH - 2, y); + g.drawLine(x + WIDTH - 1, y + 1, x + WIDTH - 1, y + HEIGHT - 2); + g.drawLine(x + 1, y + HEIGHT - 1, x + WIDTH - 2, y + HEIGHT - 1); + g.drawLine(x, y + 1, x, y + HEIGHT - 2); + } + + /** + * {@return standardized RGB value} + */ + public int getRGBValue() { + return color.getRGB(); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DefaultDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DefaultDataType.java index 837c2f778e..6e2d68c53e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DefaultDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DefaultDataType.java @@ -84,6 +84,11 @@ public class DefaultDataType extends DataTypeImpl { } } + @Override + public Class getValueClass(Settings settings) { + return Scalar.class; + } + @Override public DataType clone(DataTypeManager dtm) { return this; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java index 89e91675ea..7d52033eb0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerTypeSettingsDefinition.java @@ -4,9 +4,9 @@ * 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. @@ -35,7 +35,7 @@ public class PointerTypeSettingsDefinition private static final String[] choices = { "default", "image-base-relative", "relative", "file-offset" }; - public static final PointerTypeSettingsDefinition DEF = new PointerTypeSettingsDefinition(); // Format with HEX default + public static final PointerTypeSettingsDefinition DEF = new PointerTypeSettingsDefinition(); private PointerTypeSettingsDefinition() { } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB16ColorDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB16ColorDataType.java new file mode 100644 index 0000000000..8b97d4cfd8 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB16ColorDataType.java @@ -0,0 +1,167 @@ +/* ### + * 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.model.data; + +import java.awt.Color; +import java.util.*; + +import ghidra.docking.settings.Settings; +import ghidra.program.model.data.RGB16EncodingSettingsDefinition.RGB16Encoding; +import ghidra.program.model.mem.MemBuffer; +import ghidra.util.DataConverter; + +/** + * {@link RGB16ColorDataType} provides a base implementation for 16-bit RGB Color values. + * While this base implementation defaults to RGB_565 encoding a {@link TypeDef} + * may be established with a different 16-bit encoding specified via a default setting of + * {@link RGB16EncodingSettingsDefinition}. + */ +public class RGB16ColorDataType extends AbstractColorDataType { + + public static RGB16ColorDataType datatype = new RGB16ColorDataType(); + + private static int LENGTH = 2; + + private static TypeDefSettingsDefinition[] RGB16_TYPEDEF_SETTINGS = TypeDefSettingsDefinition + .concat(UnsignedIntegerDataType.dataType.getTypeDefSettingsDefinitions(), + RGB16EncodingSettingsDefinition.DEF); + + /** + * Generate a 16-bit RGB typedef with a specific encoding + * @param rgb16Encoding 16-bit RGB encoding + * @return RGB16 typedef + */ + public static TypedefDataType createRGB16Typedef(RGB16Encoding rgb16Encoding) { + Objects.requireNonNull(rgb16Encoding, "RGB16Encoding required"); + TypedefDataType dt = new TypedefDataType(rgb16Encoding.name(), datatype); + Settings settings = dt.getDefaultSettings(); + RGB16EncodingSettingsDefinition.DEF.setRGBEncoding(settings, rgb16Encoding); + return dt; + } + + public RGB16ColorDataType() { + this(null); + } + + public RGB16ColorDataType(DataTypeManager dtm) { + super("RGB16", dtm); + } + + @Override + public DataType clone(DataTypeManager dtm) { + if (dtm == getDataTypeManager()) { + return this; + } + return new RGB16ColorDataType(dtm); + } + + @Override + public int getLength() { + return LENGTH; + } + + @Override + public String getDescription() { + return "An RGB color with 16-bit encoding (default encoding is RGB_565, use Typedef for other 16-bit encodings)"; + } + + @Override + public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() { + return RGB16_TYPEDEF_SETTINGS; + } + + @Override + protected Color decodeColor(MemBuffer buf, Settings settings) { + + byte[] bytes = new byte[LENGTH]; + buf.getBytes(bytes, 0); + + int value = DataConverter.getInstance(ENDIAN.isBigEndian(settings, buf)).getShort(bytes, 0); + int argbValue = 0; // scaled ARGB_8888 value + + // Convert encoding to default ARGB_8888 value used by Java Color instantiation + RGB16Encoding rgbEncoding = RGB16EncodingSettingsDefinition.DEF.getRGBEncoding(settings); + switch (rgbEncoding) { + case RGB_565: + argbValue = 0xff << 24; // Alpha (enabled) + argbValue |= scaleFieldValue(getFieldValue(value, 11, 0x1f), 5) << 16; // R + argbValue |= scaleFieldValue(getFieldValue(value, 6, 0x3f), 6) << 8; // G + argbValue |= scaleFieldValue(getFieldValue(value, 0, 0x1f), 5); // B + break; + case RGB_555: { + argbValue = 0xff << 24; // Alpha (enabled) + argbValue |= scaleFieldValue(getFieldValue(value, 10, 0x1f), 5) << 16; // R + argbValue |= scaleFieldValue(getFieldValue(value, 5, 0x1f), 5) << 8; // G + argbValue |= scaleFieldValue(getFieldValue(value, 0, 0x1f), 5); // B + break; + } + case ARGB_1555: { + argbValue = (0xff * getFieldValue(value, 15, 0x1)) << 24; // Alpha + argbValue |= scaleFieldValue(getFieldValue(value, 10, 0x1f), 5) << 16; // R + argbValue |= scaleFieldValue(getFieldValue(value, 5, 0x1f), 5) << 8; // G + argbValue |= scaleFieldValue(getFieldValue(value, 0, 0x1f), 5); // B + break; + } + default: + throw new AssertionError("Missing RGB16 Encoding support: " + rgbEncoding); + } + + // 32-bit ARGB_8888 Encoding is used by Java Color + return new Color(argbValue, true); + } + + @Override + protected String getEncodingName(Settings settings) { + return RGB16EncodingSettingsDefinition.DEF.getRGBEncoding(settings).name(); + } + + @Override + protected List getComponentValues(MemBuffer buf, Settings settings) { + + byte[] bytes = new byte[LENGTH]; + buf.getBytes(bytes, 0); + + int value = DataConverter.getInstance(ENDIAN.isBigEndian(settings, buf)).getShort(bytes, 0); + + List list = new ArrayList<>(); + + RGB16Encoding rgbEncoding = RGB16EncodingSettingsDefinition.DEF.getRGBEncoding(settings); + switch (rgbEncoding) { + case RGB_565: + list.add(new ComponentValue("R", getFieldValue(value, 11, 0x1f), 5)); + list.add(new ComponentValue("G", getFieldValue(value, 6, 0x3f), 6)); + list.add(new ComponentValue("B", getFieldValue(value, 0, 0x1f), 5)); + break; + case RGB_555: { + list.add(new ComponentValue("R", getFieldValue(value, 10, 0x1f), 5)); + list.add(new ComponentValue("G", getFieldValue(value, 5, 0x1f), 5)); + list.add(new ComponentValue("B", getFieldValue(value, 0, 0x1f), 5)); + break; + } + case ARGB_1555: { + list.add(new ComponentValue("A", getFieldValue(value, 15, 0x1), 1)); + list.add(new ComponentValue("R", getFieldValue(value, 10, 0x1f), 5)); + list.add(new ComponentValue("G", getFieldValue(value, 5, 0x1f), 5)); + list.add(new ComponentValue("B", getFieldValue(value, 0, 0x1f), 5)); + break; + } + default: + throw new AssertionError("Missing RGB16 Encoding support: " + rgbEncoding); + } + return list; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB16EncodingSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB16EncodingSettingsDefinition.java new file mode 100644 index 0000000000..b063063c80 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB16EncodingSettingsDefinition.java @@ -0,0 +1,182 @@ +/* ### + * 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.model.data; + +import java.util.NoSuchElementException; + +import ghidra.docking.settings.EnumSettingsDefinition; +import ghidra.docking.settings.Settings; + +/** + * The typedef settings definition which specifies a 16-bit RGB Color Encoding + */ +public class RGB16EncodingSettingsDefinition + implements EnumSettingsDefinition, TypeDefSettingsDefinition { + + public enum RGB16Encoding { + RGB_565, RGB_555, ARGB_1555; + } + + public static final RGB16Encoding DEFAULT_ENCODING = RGB16Encoding.RGB_565; + + private static final String RGB16_ENCODING_SETTINGS_NAME = "rgb16"; + private static final String DESCRIPTION = "Specifies a 16-bit RGB Color Encoding"; + private static final String DISPLAY_NAME = "RGB16 Encoding"; + + private static final String[] choices = { RGB16Encoding.RGB_565.name(), + RGB16Encoding.RGB_555.name(), RGB16Encoding.ARGB_1555.name() }; + + public static final RGB16EncodingSettingsDefinition DEF = new RGB16EncodingSettingsDefinition(); + + private RGB16EncodingSettingsDefinition() { + } + + /** + * Returns the RGB encoding standard based on the specified settings + * @param settings the instance settings or null for default value. + * @return the RGB encoding standard. The default encoding will be returned + * if no setting has been made. + */ + public RGB16Encoding getRGBEncoding(Settings settings) { + return RGB16Encoding.valueOf(getValueString(settings)); + } + + @Override + public int getChoice(Settings settings) { + if (settings == null) { + return 0; + } + Long value = settings.getLong(RGB16_ENCODING_SETTINGS_NAME); + if (value == null) { + return 0; + } + int choice = (int) value.longValue(); + try { + if (choice >= 0 || choice < choices.length) { + return choice; + } + } + catch (NoSuchElementException e) { + // ignore + } + return 0; + } + + @Override + public String getValueString(Settings settings) { + return choices[getChoice(settings)]; + } + + @Override + public void setChoice(Settings settings, int choice) { + try { + if (choice > 0 || choice < choices.length) { + // non-default encoding setting + settings.setLong(RGB16_ENCODING_SETTINGS_NAME, choice); + return; + } + } + catch (NoSuchElementException e) { + // ignore + } + settings.clearSetting(RGB16_ENCODING_SETTINGS_NAME); + } + + public void setRGBEncoding(Settings settings, RGB16Encoding encoding) { + String encodingName = encoding.name(); + for (int i = 0; i < choices.length; i++) { + if (choices[i].equals(encodingName)) { + setChoice(settings, i); + break; + } + } + throw new AssertionError("Missing RGB Encoding choice: " + encoding); + } + + @Override + public String[] getDisplayChoices(Settings settings) { + return choices; + } + + @Override + public String getName() { + return DISPLAY_NAME; + } + + @Override + public String getStorageKey() { + return RGB16_ENCODING_SETTINGS_NAME; + } + + @Override + public String getDescription() { + return DESCRIPTION; + } + + @Override + public String getDisplayChoice(int value, Settings s1) { + return choices[value]; + } + + @Override + public void clear(Settings settings) { + settings.clearSetting(RGB16_ENCODING_SETTINGS_NAME); + } + + @Override + public void copySetting(Settings settings, Settings destSettings) { + Long l = settings.getLong(RGB16_ENCODING_SETTINGS_NAME); + if (l == null) { + destSettings.clearSetting(RGB16_ENCODING_SETTINGS_NAME); + } + else { + destSettings.setLong(RGB16_ENCODING_SETTINGS_NAME, l); + } + } + + @Override + public boolean hasValue(Settings setting) { + return setting.getValue(RGB16_ENCODING_SETTINGS_NAME) != null; + } + + public String getDisplayChoice(Settings settings) { + return choices[getChoice(settings)]; + } + + /** + * Sets the settings object to the enum value indicating the specified choice as a string. + * @param settings the settings to store the value. + * @param choice enum string representing a choice in the enum. + */ + public void setDisplayChoice(Settings settings, String choice) { + for (int i = 0; i < choices.length; i++) { + if (choices[i].equals(choice)) { + setChoice(settings, i); + break; + } + } + } + + @Override + public String getAttributeSpecification(Settings settings) { + int choice = getChoice(settings); + if (choice != 0) { + return choices[choice]; + } + return null; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB32ColorDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB32ColorDataType.java new file mode 100644 index 0000000000..fb4cc3c0d5 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB32ColorDataType.java @@ -0,0 +1,172 @@ +/* ### + * 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.model.data; + +import java.awt.Color; +import java.util.*; + +import ghidra.docking.settings.Settings; +import ghidra.program.model.data.RGB32EncodingSettingsDefinition.RGB32Encoding; +import ghidra.program.model.mem.MemBuffer; +import ghidra.util.DataConverter; + +/** + * {@link RGB32ColorDataType} provides a base implementation for 32-bit RGB Color values with + * an Alpha channel. While this base implementation defaults to ARGB_8888 encoding a {@link TypeDef} + * may be established with a different 32-bit encoding specified via a default setting of + * {@link RGB32EncodingSettingsDefinition}. + */ +public class RGB32ColorDataType extends AbstractColorDataType { + + public static RGB32ColorDataType datatype = new RGB32ColorDataType(); + + private static int LENGTH = 4; + + private static TypeDefSettingsDefinition[] RGB32_TYPEDEF_SETTINGS = TypeDefSettingsDefinition + .concat(UnsignedIntegerDataType.dataType.getTypeDefSettingsDefinitions(), + RGB32EncodingSettingsDefinition.DEF); + + /** + * Generate a 32-bit RGB typedef with a specific encoding + * @param rgb32Encoding 32-bit RGB encoding + * @return RGB32 typedef + */ + public static TypedefDataType createRGB32Typedef(RGB32Encoding rgb32Encoding) { + Objects.requireNonNull(rgb32Encoding, "RGB32Encoding required"); + TypedefDataType dt = new TypedefDataType(rgb32Encoding.name(), datatype); + Settings settings = dt.getDefaultSettings(); + RGB32EncodingSettingsDefinition.DEF.setRGBEncoding(settings, rgb32Encoding); + return dt; + } + + public RGB32ColorDataType() { + this(null); + } + + public RGB32ColorDataType(DataTypeManager dtm) { + super("RGB32", dtm); + } + + @Override + public DataType clone(DataTypeManager dtm) { + if (dtm == getDataTypeManager()) { + return this; + } + return new RGB32ColorDataType(dtm); + } + + @Override + public int getLength() { + return LENGTH; + } + + @Override + public String getDescription() { + return "An RGB color with 32-bit encoding (default encoding is ARGB_8888, use Typedef for other 32-bit encodings)"; + } + + @Override + public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() { + return RGB32_TYPEDEF_SETTINGS; + } + + @Override + protected Color decodeColor(MemBuffer buf, Settings settings) { + + byte[] bytes = new byte[LENGTH]; + buf.getBytes(bytes, 0); + + int value = DataConverter.getInstance(ENDIAN.isBigEndian(settings, buf)).getInt(bytes, 0); + + // Convert encoding to 32-bit ARGB_8888 value used by Java Color instantiation + RGB32Encoding rgbEncoding = RGB32EncodingSettingsDefinition.DEF.getRGBEncoding(settings); + switch (rgbEncoding) { + case ARGB_8888: + break; + case RGBA_8888: { + int alpha = value & 0xff; + int rgb = value >>> 8; + value = rgb + (alpha << 24); + break; + } + case BGRA_8888: { + value = Integer.reverseBytes(value); + break; + } + case ABGR_8888: { + int rgb = Integer.reverseBytes(value) >>> 8; + value = rgb + (value & 0xff000000); + break; + } + default: + throw new AssertionError("Missing RGB32 Encoding support: " + rgbEncoding); + } + + // 32-bit ARGB_8888 Encoding is used by Java Color + return new Color(value, true); + } + + @Override + protected String getEncodingName(Settings settings) { + return RGB32EncodingSettingsDefinition.DEF.getRGBEncoding(settings).name(); + } + + @Override + protected List getComponentValues(MemBuffer buf, Settings settings) { + + byte[] bytes = new byte[LENGTH]; + buf.getBytes(bytes, 0); + + int value = DataConverter.getInstance(ENDIAN.isBigEndian(settings, buf)).getInt(bytes, 0); + + List list = new ArrayList<>(); + + RGB32Encoding rgbEncoding = RGB32EncodingSettingsDefinition.DEF.getRGBEncoding(settings); + switch (rgbEncoding) { + case ARGB_8888: + list.add(new ComponentValue("A", getFieldValue(value, 24, 0xff), 8)); + list.add(new ComponentValue("R", getFieldValue(value, 16, 0xff), 8)); + list.add(new ComponentValue("G", getFieldValue(value, 8, 0xff), 8)); + list.add(new ComponentValue("B", getFieldValue(value, 0, 0xff), 8)); + break; + case RGBA_8888: { + list.add(new ComponentValue("R", getFieldValue(value, 24, 0xff), 8)); + list.add(new ComponentValue("G", getFieldValue(value, 16, 0xff), 8)); + list.add(new ComponentValue("B", getFieldValue(value, 8, 0xff), 8)); + list.add(new ComponentValue("A", getFieldValue(value, 0, 0xff), 8)); + break; + } + case BGRA_8888: { + list.add(new ComponentValue("B", getFieldValue(value, 24, 0xff), 8)); + list.add(new ComponentValue("G", getFieldValue(value, 16, 0xff), 8)); + list.add(new ComponentValue("R", getFieldValue(value, 8, 0xff), 8)); + list.add(new ComponentValue("A", getFieldValue(value, 0, 0xff), 8)); + break; + } + case ABGR_8888: { + list.add(new ComponentValue("A", getFieldValue(value, 24, 0xff), 8)); + list.add(new ComponentValue("B", getFieldValue(value, 16, 0xff), 8)); + list.add(new ComponentValue("G", getFieldValue(value, 8, 0xff), 8)); + list.add(new ComponentValue("R", getFieldValue(value, 0, 0xff), 8)); + break; + } + default: + throw new AssertionError("Missing RGB32 Encoding support: " + rgbEncoding); + } + return list; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB32EncodingSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB32EncodingSettingsDefinition.java new file mode 100644 index 0000000000..937dca2e46 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/RGB32EncodingSettingsDefinition.java @@ -0,0 +1,183 @@ +/* ### + * 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.model.data; + +import java.util.NoSuchElementException; + +import ghidra.docking.settings.EnumSettingsDefinition; +import ghidra.docking.settings.Settings; + +/** + * The typedef settings definition which specifies a 32-bit RGB Color Encoding + */ +public class RGB32EncodingSettingsDefinition + implements EnumSettingsDefinition, TypeDefSettingsDefinition { + + public enum RGB32Encoding { + ARGB_8888, RGBA_8888, BGRA_8888, ABGR_8888; + } + + public static final RGB32Encoding DEFAULT_ENCODING = RGB32Encoding.ARGB_8888; + + private static final String RGB32_ENCODING_SETTINGS_NAME = "rgb32"; + private static final String DESCRIPTION = "Specifies a 32-bit RGB Color Encoding"; + private static final String DISPLAY_NAME = "RGB32 Encoding"; + + private static final String[] choices = + { RGB32Encoding.ARGB_8888.name(), RGB32Encoding.RGBA_8888.name(), + RGB32Encoding.BGRA_8888.name(), RGB32Encoding.ABGR_8888.name() }; + + public static final RGB32EncodingSettingsDefinition DEF = new RGB32EncodingSettingsDefinition(); + + private RGB32EncodingSettingsDefinition() { + } + + /** + * Returns the RGB encoding standard based on the specified settings + * @param settings the instance settings or null for default value. + * @return the RGB encoding standard. The default encoding will be returned + * if no setting has been made. + */ + public RGB32Encoding getRGBEncoding(Settings settings) { + return RGB32Encoding.valueOf(getValueString(settings)); + } + + @Override + public int getChoice(Settings settings) { + if (settings == null) { + return 0; + } + Long value = settings.getLong(RGB32_ENCODING_SETTINGS_NAME); + if (value == null) { + return 0; + } + int choice = (int) value.longValue(); + try { + if (choice >= 0 || choice < choices.length) { + return choice; + } + } + catch (NoSuchElementException e) { + // ignore + } + return 0; + } + + @Override + public String getValueString(Settings settings) { + return choices[getChoice(settings)]; + } + + @Override + public void setChoice(Settings settings, int choice) { + try { + if (choice > 0 || choice < choices.length) { + // non-default encoding setting + settings.setLong(RGB32_ENCODING_SETTINGS_NAME, choice); + return; + } + } + catch (NoSuchElementException e) { + // ignore + } + settings.clearSetting(RGB32_ENCODING_SETTINGS_NAME); + } + + public void setRGBEncoding(Settings settings, RGB32Encoding encoding) { + String encodingName = encoding.name(); + for (int i = 0; i < choices.length; i++) { + if (choices[i].equals(encodingName)) { + setChoice(settings, i); + break; + } + } + throw new AssertionError("Missing RGB Encoding choice: " + encoding); + } + + @Override + public String[] getDisplayChoices(Settings settings) { + return choices; + } + + @Override + public String getName() { + return DISPLAY_NAME; + } + + @Override + public String getStorageKey() { + return RGB32_ENCODING_SETTINGS_NAME; + } + + @Override + public String getDescription() { + return DESCRIPTION; + } + + @Override + public String getDisplayChoice(int value, Settings s1) { + return choices[value]; + } + + @Override + public void clear(Settings settings) { + settings.clearSetting(RGB32_ENCODING_SETTINGS_NAME); + } + + @Override + public void copySetting(Settings settings, Settings destSettings) { + Long l = settings.getLong(RGB32_ENCODING_SETTINGS_NAME); + if (l == null) { + destSettings.clearSetting(RGB32_ENCODING_SETTINGS_NAME); + } + else { + destSettings.setLong(RGB32_ENCODING_SETTINGS_NAME, l); + } + } + + @Override + public boolean hasValue(Settings setting) { + return setting.getValue(RGB32_ENCODING_SETTINGS_NAME) != null; + } + + public String getDisplayChoice(Settings settings) { + return choices[getChoice(settings)]; + } + + /** + * Sets the settings object to the enum value indicating the specified choice as a string. + * @param settings the settings to store the value. + * @param choice enum string representing a choice in the enum. + */ + public void setDisplayChoice(Settings settings, String choice) { + for (int i = 0; i < choices.length; i++) { + if (choices[i].equals(choice)) { + setChoice(settings, i); + break; + } + } + } + + @Override + public String getAttributeSpecification(Settings settings) { + int choice = getChoice(settings); + if (choice != 0) { + return choices[choice]; + } + return null; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java index 456393b106..e9c594702a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypeDefSettingsDefinition.java @@ -4,9 +4,9 @@ * 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. @@ -41,4 +41,27 @@ public interface TypeDefSettingsDefinition extends SettingsDefinition { */ String getAttributeSpecification(Settings settings); + /** + * Create a new list of {@link TypeDefSettingsDefinition}s by concat'ing a base list with + * a var-arg'ish additional list of setting defs. Any additional duplicates are discarded. + * @param settings List of settings defs. + * @param additional More settings defs to add + * @return new array with all the settings defs joined together. + */ + public static TypeDefSettingsDefinition[] concat(TypeDefSettingsDefinition[] settings, + TypeDefSettingsDefinition... additional) { + if (additional == null) { + return settings; + } + if (settings == null) { + return additional; + } + + TypeDefSettingsDefinition[] newArray = + new TypeDefSettingsDefinition[settings.length + additional.length]; + System.arraycopy(settings, 0, newArray, 0, settings.length); + System.arraycopy(additional, 0, newArray, settings.length, additional.length); + return newArray; + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Data.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Data.java index 946467823f..c27ad40135 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Data.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Data.java @@ -21,6 +21,7 @@ import ghidra.docking.settings.Settings; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataTypeDisplayOptions; +import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.Reference; @@ -30,8 +31,10 @@ import ghidra.program.model.symbol.Reference; public interface Data extends CodeUnit, Settings { /** - * Returns the value of the data item. The value may be an address, a scalar, - * register or null if no value. + * Returns the value of this data as determined by the corresponding {@link DataType}. + * The value may be an {@link Address}, {@link Scalar}, a datatype-defined object or null + * if no value. + * * @return the value */ public Object getValue(); @@ -42,7 +45,7 @@ public interface Data extends CodeUnit, Settings { *

NOTE: This determination is made based upon data type and settings only and does not * examine memory bytes which are used to construct the data value object. * - * @return value class or null if a consistent class is not utilized. + * @return value class or null if a consistent value class is not utilized. */ public Class getValueClass();