mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 16:40:08 +00:00
GP-1403-3 Improved datatype preview formatting. Datatype Diff may not
tolerate formating changes. More work is needed.
This commit is contained in:
parent
8f0589a6d8
commit
332480a422
@ -100,30 +100,31 @@ public class ToolTipUtils {
|
||||
*/
|
||||
public static HTMLDataTypeRepresentation getHTMLRepresentation(DataType dataType) {
|
||||
if (dataType != null) {
|
||||
if (dataType instanceof BuiltIn) {
|
||||
return new DefaultDataTypeHTMLRepresentation(dataType);
|
||||
}
|
||||
if (dataType instanceof TypeDef) {
|
||||
return new TypeDefDataTypeHTMLRepresentation((TypeDef) dataType);
|
||||
}
|
||||
else if (dataType instanceof Composite) {
|
||||
if (dataType instanceof Composite) {
|
||||
return new CompositeDataTypeHTMLRepresentation((Composite) dataType);
|
||||
}
|
||||
else if (dataType instanceof Enum) {
|
||||
if (dataType instanceof Enum) {
|
||||
return new EnumDataTypeHTMLRepresentation((Enum) dataType);
|
||||
}
|
||||
else if (dataType instanceof FunctionDefinition) {
|
||||
if (dataType instanceof FunctionDefinition) {
|
||||
return new FunctionDataTypeHTMLRepresentation((FunctionDefinition) dataType);
|
||||
}
|
||||
else if (dataType instanceof Pointer) {
|
||||
if (dataType instanceof Pointer) {
|
||||
return new PointerDataTypeHTMLRepresentation((Pointer) dataType);
|
||||
}
|
||||
else if (dataType instanceof Array) {
|
||||
if (dataType instanceof Array) {
|
||||
return new ArrayDataTypeHTMLRepresentation((Array) dataType);
|
||||
}
|
||||
else if (dataType instanceof BitFieldDataType) {
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
return new BitFieldDataTypeHTMLRepresentation((BitFieldDataType) dataType);
|
||||
}
|
||||
else {
|
||||
return new DefaultDataTypeHTMLRepresentation(dataType);
|
||||
}
|
||||
return new DefaultDataTypeHTMLRepresentation(dataType);
|
||||
}
|
||||
|
||||
return new NullDataTypeHTMLRepresentation();
|
||||
|
@ -48,7 +48,11 @@ public class DataTypeUrl {
|
||||
*/
|
||||
public DataTypeUrl(DataType dt) {
|
||||
DataTypeManager dtm = dt.getDataTypeManager();
|
||||
dataTypeManagerId = Objects.requireNonNull(dtm.getUniversalID());
|
||||
if (dtm == null) {
|
||||
// Tolerate tests which may produce datatypes without datatype manager
|
||||
dtm = BuiltInDataTypeManager.getDataTypeManager();
|
||||
}
|
||||
dataTypeManagerId = dtm.getUniversalID();
|
||||
dataTypeId = dt.getUniversalID();
|
||||
dataTypeName = Objects.requireNonNull(dt.getName());
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ package ghidra.app.util.html;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.diff.DataTypeDiff;
|
||||
import ghidra.app.util.html.diff.DataTypeDiffBuilder;
|
||||
@ -72,16 +74,22 @@ public class ArrayDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
|
||||
DataType baseDataType = getBaseDataType();
|
||||
buffy.append("Array Base Data Type: ").append(BR);
|
||||
buffy.append(INDENT_OPEN);
|
||||
|
||||
if (baseDataType instanceof BuiltInDataType) {
|
||||
String simpleName = baseDataType.getClass().getSimpleName();
|
||||
buffy.append(simpleName);
|
||||
addDataTypeLength(baseDataType, buffy);
|
||||
String simpleName = baseDataType.getDisplayName();
|
||||
buffy.append(TT_OPEN).append(simpleName).append(TT_CLOSE);
|
||||
buffy.append(BR).append(INDENT_OPEN);
|
||||
|
||||
String description = baseDataType.getDescription();
|
||||
if (!StringUtils.isBlank(description)) {
|
||||
String encodedDescription =
|
||||
HTMLUtilities.friendlyEncodeHTML(description);
|
||||
buffy.append(encodedDescription).append(BR);
|
||||
}
|
||||
addDataTypeLengthAndAlignment(baseDataType, buffy);
|
||||
buffy.append(INDENT_CLOSE);
|
||||
}
|
||||
else {
|
||||
|
||||
HTMLDataTypeRepresentation representation =
|
||||
ToolTipUtils.getHTMLRepresentation(baseDataType);
|
||||
|
||||
@ -93,18 +101,15 @@ public class ArrayDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation
|
||||
buffy.append(baseHTML);
|
||||
|
||||
if (baseHTML.indexOf(LENGTH_PREFIX) < 0) {
|
||||
addDataTypeLength(baseDataType, buffy);
|
||||
addDataTypeLengthAndAlignment(baseDataType, buffy);
|
||||
}
|
||||
}
|
||||
|
||||
buffy.append(INDENT_CLOSE);
|
||||
|
||||
return buffy.toString();
|
||||
}
|
||||
|
||||
private ValidatableLine buildHeaderContent() {
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
buffy.append(FORWARD_SLASH).append(FORWARD_SLASH).append(HTML_SPACE);
|
||||
buffy.append(HTMLUtilities.friendlyEncodeHTML(array.getName()));
|
||||
return new TextLine(buffy.toString());
|
||||
}
|
||||
@ -112,9 +117,9 @@ public class ArrayDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation
|
||||
private ValidatableLine buildFooterContent() {
|
||||
int len = array.getLength();
|
||||
if (array.isZeroLength()) {
|
||||
return new TextLine("Size: 0 (reported size is " + len + ")");
|
||||
return new TextLine(LENGTH_PREFIX + "0 (reported length is " + len + ")");
|
||||
}
|
||||
return new TextLine("Size: " + len);
|
||||
return new TextLine(LENGTH_PREFIX + len);
|
||||
}
|
||||
|
||||
private String buildHTMLText(ValidatableLine header, String body, ValidatableLine info,
|
||||
@ -130,13 +135,13 @@ public class ArrayDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation
|
||||
headerText = wrapStringInColor(headerText, headerLine.getTextColor());
|
||||
buffy.append(headerText);
|
||||
|
||||
buffy.append(BR);
|
||||
TextLine infoLine = (TextLine) info;
|
||||
buffy.append(INDENT_OPEN);
|
||||
TextLine infoLine = (TextLine) info; // TODO: Should include Alignment as well as Length (using footer prevents this)
|
||||
String infoText = info.getText();
|
||||
infoText = wrapStringInColor(infoText, infoLine.getTextColor());
|
||||
buffy.append(infoText);
|
||||
|
||||
buffy.append(BR).append(BR);
|
||||
buffy.append(BR).append(BR).append(INDENT_CLOSE);
|
||||
buffy.append(body);
|
||||
|
||||
return buffy.toString();
|
||||
|
@ -21,10 +21,8 @@ import java.awt.Color;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.datatype.DataTypeUrl;
|
||||
import ghidra.app.util.html.diff.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
|
||||
@ -40,8 +38,6 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
protected List<ValidatableLine> alignmentText;
|
||||
protected TextLine alignmentValueText;
|
||||
|
||||
protected static final String ALIGNMENT_VALUE_PREFIX = "Alignment: ";
|
||||
|
||||
private String truncatedHtmlData;
|
||||
|
||||
// private constructor for making diff copies
|
||||
@ -90,14 +86,6 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextLine buildFooterText(DataType dataType) {
|
||||
if (dataType.isZeroLength()) {
|
||||
return new TextLine("0");
|
||||
}
|
||||
return super.buildFooterText(dataType);
|
||||
}
|
||||
|
||||
protected List<ValidatableLine> buildAlignmentText(Composite dataType) {
|
||||
List<ValidatableLine> list = new ArrayList<>();
|
||||
String alignStr = CompositeInternal.getMinAlignmentString(dataType);
|
||||
@ -118,8 +106,20 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
private List<ValidatableLine> buildContent(Composite comp) {
|
||||
List<ValidatableLine> list = new ArrayList<>();
|
||||
int count = 0;
|
||||
DataTypeComponent[] components = comp.getComponents();
|
||||
boolean showPadding = (comp instanceof Structure) && !comp.isPackingEnabled();
|
||||
int nextPadStart = 0;
|
||||
int length = comp.isZeroLength() ? 0 : comp.getLength();
|
||||
DataTypeComponent[] components = comp.getDefinedComponents();
|
||||
for (DataTypeComponent dataTypeComponent : components) {
|
||||
|
||||
int offset = dataTypeComponent.getOffset();
|
||||
if (showPadding && offset > nextPadStart) {
|
||||
int padLen = offset - nextPadStart;
|
||||
list.add(new TextLine("-- " + padLen + " undefined bytes at offset 0x" +
|
||||
Long.toHexString(nextPadStart) + " --"));
|
||||
}
|
||||
nextPadStart = dataTypeComponent.getEndOffset() + 1;
|
||||
|
||||
String fieldName = dataTypeComponent.getFieldName();
|
||||
String comment = dataTypeComponent.getComment();
|
||||
|
||||
@ -139,6 +139,11 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (showPadding && length > nextPadStart) {
|
||||
int padLen = length - nextPadStart;
|
||||
list.add(new TextLine("-- " + padLen + " undefined bytes at offset 0x" +
|
||||
Long.toHexString(nextPadStart) + " --"));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -162,21 +167,12 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
String warningLine = wrapStringInColor(warning, Color.RED);
|
||||
|
||||
//@formatter:off
|
||||
append(fullHtml, truncatedHtml, lineCount, warningLine,
|
||||
BR,
|
||||
BR);
|
||||
append(fullHtml, truncatedHtml, lineCount++, warningLine, BR);
|
||||
//@formatter:on
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
append(fullHtml, truncatedHtml, lineCount, ALIGNMENT_VALUE_PREFIX,
|
||||
alignmentValueText.getText(),
|
||||
BR);
|
||||
append(fullHtml, truncatedHtml, lineCount, LENGTH_PREFIX,
|
||||
footerText.getText(),
|
||||
BR, BR);
|
||||
//@formatter:on
|
||||
// FIXME: Only component output lines should be limited by max line count
|
||||
// and not initial/critical output which could mess-up HTML ouput (e.g., indent open/close)
|
||||
|
||||
// header
|
||||
Iterator<ValidatableLine> iterator = headerContent.iterator();
|
||||
@ -187,8 +183,7 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
text = truncateAsNecessary(text);
|
||||
}
|
||||
String headerLine = wrapStringInColor(text, line.getTextColor());
|
||||
append(fullHtml, truncatedHtml, lineCount, headerLine);
|
||||
lineCount++;
|
||||
append(fullHtml, truncatedHtml, lineCount++, headerLine);
|
||||
}
|
||||
|
||||
// "<TT> displayName</TT> { "
|
||||
@ -200,42 +195,61 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
displayNameText = wrapStringInColor(displayNameText, displayName.getTextColor());
|
||||
|
||||
//@formatter:off
|
||||
append(fullHtml, truncatedHtml, lineCount, TT_OPEN,
|
||||
append(fullHtml, truncatedHtml, lineCount++, TT_OPEN,
|
||||
displayNameText,
|
||||
TT_CLOSE,
|
||||
HTML_SPACE,
|
||||
"{",
|
||||
HTML_SPACE);
|
||||
//@formatter:on
|
||||
lineCount++;
|
||||
BR);
|
||||
|
||||
append(fullHtml, truncatedHtml, lineCount++,
|
||||
INDENT_OPEN,
|
||||
LENGTH_PREFIX,
|
||||
footerText.getText(), // length
|
||||
HTML_SPACE,
|
||||
HTML_SPACE,
|
||||
ALIGNMENT_PREFIX,
|
||||
alignmentValueText.getText(),
|
||||
INDENT_CLOSE);
|
||||
|
||||
append(fullHtml, truncatedHtml, lineCount++,
|
||||
"{",
|
||||
BR);
|
||||
|
||||
String tableOpen = "<TABLE BORDER=0 CELLSPACING=5 CELLPADDING=0>";
|
||||
//@formatter:on
|
||||
|
||||
String tableOpen = "<TABLE BORDER=0 CELLSPACING=5 CELLPADDING=0>"; // 3 columns
|
||||
fullHtml.append(tableOpen);
|
||||
truncatedHtml.append(tableOpen);
|
||||
|
||||
iterator = bodyContent.iterator();
|
||||
for (; iterator.hasNext(); lineCount++) {
|
||||
|
||||
iterator.hasNext();
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
StringBuilder lineBuffer = new StringBuilder();
|
||||
DataTypeLine line = (DataTypeLine) iterator.next();
|
||||
String typeName = generateTypeName(line, trim);
|
||||
ValidatableLine line = iterator.next();
|
||||
|
||||
if (!(line instanceof DataTypeLine)) {
|
||||
append(fullHtml, truncatedHtml, lineCount++, TR_OPEN,
|
||||
"<TD COLSPAN=3><FONT COLOR=\"gray\">", TAB, TAB,
|
||||
line.getText(), "</FONT>", TD_CLOSE, TR_CLOSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
DataTypeLine dtLine = (DataTypeLine) line;
|
||||
String typeName = generateTypeName(dtLine, trim);
|
||||
|
||||
int fieldLength = ToolTipUtils.LINE_LENGTH / 2;
|
||||
String fieldName = line.getName();
|
||||
String fieldName = dtLine.getName();
|
||||
if (trim) {
|
||||
fieldName = StringUtilities.trimMiddle(fieldName, fieldLength);
|
||||
}
|
||||
fieldName = friendlyEncodeHTML(fieldName);
|
||||
fieldName = wrapStringInColor(fieldName, line.getNameColor());
|
||||
fieldName = wrapStringInColor(fieldName, dtLine.getNameColor());
|
||||
|
||||
String typeComment = line.getComment();
|
||||
String typeComment = dtLine.getComment();
|
||||
if (trim) {
|
||||
typeComment = truncateAsNecessary(typeComment, fieldLength);
|
||||
}
|
||||
typeComment = friendlyEncodeHTML(typeComment);
|
||||
typeComment = wrapStringInColor(typeComment, line.getCommentColor());
|
||||
typeComment = wrapStringInColor(typeComment, dtLine.getCommentColor());
|
||||
|
||||
// start the table row
|
||||
lineBuffer.append(TR_OPEN);
|
||||
@ -264,7 +278,7 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
lineBuffer.append(TR_CLOSE);
|
||||
|
||||
String lineString = lineBuffer.toString();
|
||||
append(fullHtml, truncatedHtml, lineCount, lineString);
|
||||
append(fullHtml, truncatedHtml, lineCount++, lineString);
|
||||
}
|
||||
|
||||
// show ellipses if needed; the truncated html is much shorter than the full html
|
||||
@ -322,24 +336,15 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
|
||||
private static String generateTypeName(DataTypeLine line, boolean trim) {
|
||||
|
||||
String type = line.getType();
|
||||
if (true) {
|
||||
type = truncateAsNecessary(line.getType());
|
||||
}
|
||||
type = friendlyEncodeHTML(type);
|
||||
type = wrapStringInColor(type, line.getTypeColor());
|
||||
|
||||
if (!line.hasUniversalId()) {
|
||||
return type;
|
||||
}
|
||||
|
||||
//
|
||||
// Markup the name with info for later hyperlink capability, as needed by the client
|
||||
//
|
||||
Color color = line.getTypeColor();
|
||||
DataType dt = line.getDataType();
|
||||
DataTypeUrl url = new DataTypeUrl(dt);
|
||||
String wrapped = HTMLUtilities.wrapWithLinkPlaceholder(type, url.toString());
|
||||
return wrapped;
|
||||
if (dt != null) {
|
||||
return generateTypeName(dt, color, trim);
|
||||
}
|
||||
|
||||
String type = truncateAsNecessary(line.getType());
|
||||
type = friendlyEncodeHTML(type);
|
||||
return wrapStringInColor(type, line.getTypeColor());
|
||||
}
|
||||
|
||||
// overridden to return truncated text by default
|
||||
|
@ -21,7 +21,6 @@ import java.util.Objects;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.StringUtilities;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class DataTypeLine implements ValidatableLine {
|
||||
|
||||
@ -105,6 +104,11 @@ public class DataTypeLine implements ValidatableLine {
|
||||
this.commentColor = commentColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(Color color) {
|
||||
setAllColors(color);
|
||||
}
|
||||
|
||||
void setAllColors(Color diffColor) {
|
||||
setNameColor(diffColor);
|
||||
setTypeColor(diffColor);
|
||||
@ -125,9 +129,10 @@ public class DataTypeLine implements ValidatableLine {
|
||||
}
|
||||
|
||||
if (!(otherValidatableLine instanceof DataTypeLine)) {
|
||||
throw new AssertException("DataTypeLine can only be matched against other " +
|
||||
"DataTypeLine implementations.");
|
||||
otherValidatableLine.setTextColor(invalidColor);
|
||||
return;
|
||||
}
|
||||
|
||||
DataTypeLine otherLine = (DataTypeLine) otherValidatableLine;
|
||||
|
||||
// note: use the other line here, so if it is a special, overridden case, then we will
|
||||
@ -205,8 +210,7 @@ public class DataTypeLine implements ValidatableLine {
|
||||
}
|
||||
|
||||
if (!(otherValidatableLine instanceof DataTypeLine)) {
|
||||
throw new AssertException("DataTypeLine can only be matched against other " +
|
||||
"DataTypeLine implementations.");
|
||||
return false;
|
||||
}
|
||||
DataTypeLine otherLine = (DataTypeLine) otherValidatableLine;
|
||||
|
||||
|
@ -17,8 +17,6 @@ package ghidra.app.util.html;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class EmptyDataTypeLine extends DataTypeLine implements PlaceHolderLine {
|
||||
public EmptyDataTypeLine() {
|
||||
super("", "", "", null);
|
||||
@ -39,14 +37,8 @@ public class EmptyDataTypeLine extends DataTypeLine implements PlaceHolderLine {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(otherValidatableLine instanceof DataTypeLine)) {
|
||||
throw new AssertException("DataTypeLine can only be matched against other " +
|
||||
"DataTypeLine implementations.");
|
||||
}
|
||||
DataTypeLine otherLine = (DataTypeLine) otherValidatableLine;
|
||||
|
||||
// since we are the empty line, the other line is all a mismatch
|
||||
otherLine.setAllColors(invalidColor);
|
||||
otherValidatableLine.setTextColor(invalidColor);
|
||||
}
|
||||
|
||||
boolean matches(DataTypeLine otherLine) {
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.html;
|
||||
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class EmptyTextLine extends TextLine implements PlaceHolderLine {
|
||||
@ -61,14 +59,8 @@ public class EmptyTextLine extends TextLine implements PlaceHolderLine {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(otherValidatableLine instanceof TextLine)) {
|
||||
throw new AssertException("TextLine can only be matched against other "
|
||||
+ "TextLine implementations.");
|
||||
}
|
||||
TextLine otherLine = (TextLine) otherValidatableLine;
|
||||
|
||||
// since we are the empty line, the other line is all a mismatch
|
||||
otherLine.setTextColor(invalidColor);
|
||||
otherValidatableLine.setTextColor(invalidColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,8 +17,6 @@ package ghidra.app.util.html;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class EmptyVariableTextLine extends VariableTextLine implements PlaceHolderLine {
|
||||
|
||||
private int numberOfCharacters;
|
||||
@ -54,14 +52,9 @@ public class EmptyVariableTextLine extends VariableTextLine implements PlaceHold
|
||||
(otherValidatableLine instanceof EmptyVariableTextLine)) {
|
||||
return;
|
||||
}
|
||||
if (!(otherValidatableLine instanceof VariableTextLine)) {
|
||||
throw new AssertException("VariableTextLine can only be matched against other " +
|
||||
"VariableTextLine implementations.");
|
||||
}
|
||||
VariableTextLine otherLine = (VariableTextLine) otherValidatableLine;
|
||||
|
||||
// since we are the empty line, the other line is all a mismatch
|
||||
otherLine.setAllColors(invalidColor);
|
||||
otherValidatableLine.setTextColor(invalidColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,9 +144,6 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
append(fullHtml, truncatedHtml, lineCount, LENGTH_PREFIX, infoLine.getText());
|
||||
append(fullHtml, truncatedHtml, lineCount, BR, BR);
|
||||
|
||||
// "<TT> displayName { "
|
||||
String displayNameText = displayName.getText();
|
||||
if (trim) {
|
||||
@ -155,15 +152,17 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
|
||||
displayNameText = HTMLUtilities.friendlyEncodeHTML(displayNameText);
|
||||
displayNameText = wrapStringInColor(displayNameText, displayName.getTextColor());
|
||||
//@formatter:off
|
||||
append(fullHtml, truncatedHtml, lineCount, TT_OPEN,
|
||||
append(fullHtml, truncatedHtml, lineCount++, TT_OPEN,
|
||||
displayNameText,
|
||||
TT_CLOSE,
|
||||
HTML_SPACE,
|
||||
"{",
|
||||
HTML_SPACE,
|
||||
BR);
|
||||
|
||||
// TODO: show alignment
|
||||
append(fullHtml, truncatedHtml, lineCount++, INDENT_OPEN, LENGTH_PREFIX, infoLine.getText(), INDENT_CLOSE);
|
||||
|
||||
append(fullHtml, truncatedHtml, lineCount++, "{", BR);
|
||||
|
||||
//@formatter:on
|
||||
lineCount++;
|
||||
|
||||
int length = bodyLines.size();
|
||||
for (int i = 0; i < length; i++, lineCount++) {
|
||||
|
@ -15,10 +15,13 @@
|
||||
*/
|
||||
package ghidra.app.util.html;
|
||||
|
||||
import static ghidra.util.HTMLUtilities.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.app.util.datatype.DataTypeUrl;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
@ -77,6 +80,7 @@ public abstract class HTMLDataTypeRepresentation {
|
||||
|
||||
protected static final String ELLIPSES = "...";
|
||||
protected static final String LENGTH_PREFIX = "Length: ";
|
||||
protected static final String ALIGNMENT_PREFIX = "Alignment: ";
|
||||
|
||||
protected final static String FORWARD_SLASH = "/";
|
||||
|
||||
@ -104,12 +108,17 @@ public abstract class HTMLDataTypeRepresentation {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected static StringBuilder addDataTypeLength(DataType dt, StringBuilder buffer) {
|
||||
protected static StringBuilder addDataTypeLengthAndAlignment(DataType dt,
|
||||
StringBuilder buffer) {
|
||||
|
||||
buffer.append(BR);
|
||||
buffer.append(LENGTH_PREFIX);
|
||||
buffer.append(getDataTypeLengthString(dt));
|
||||
|
||||
if (dt != null && dt.getLength() >= 0) {
|
||||
buffer.append(HTML_SPACE);
|
||||
buffer.append(HTML_SPACE);
|
||||
buffer.append(ALIGNMENT_PREFIX);
|
||||
buffer.append(dt.getAlignment());
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -119,7 +128,7 @@ public abstract class HTMLDataTypeRepresentation {
|
||||
lengthString = "<i>Unknown</i>";
|
||||
}
|
||||
else {
|
||||
int length = dt.getLength();
|
||||
int length = dt.isZeroLength() ? 0 : dt.getLength();
|
||||
if (length >= 0) {
|
||||
lengthString = Integer.toString(length);
|
||||
}
|
||||
@ -380,18 +389,115 @@ public abstract class HTMLDataTypeRepresentation {
|
||||
headerLines.addAll(createCommentLines(comment, 4));
|
||||
|
||||
// put the path info in; don't display a floating '/' when the path is the root path
|
||||
CategoryPath path = dataType.getCategoryPath();
|
||||
if (!path.equals(CategoryPath.ROOT)) {
|
||||
headerLines.add(new TextLine(HTMLUtilities.escapeHTML(path.getPath())));
|
||||
headerLines.add(new TextLine(BR));
|
||||
}
|
||||
// CategoryPath path = dataType.getCategoryPath();
|
||||
// if (!path.equals(CategoryPath.ROOT)) {
|
||||
// headerLines.add(new TextLine(HTMLUtilities.escapeHTML(path.getPath())));
|
||||
// headerLines.add(new TextLine(BR));
|
||||
// }
|
||||
|
||||
return headerLines;
|
||||
}
|
||||
|
||||
protected TextLine buildFooterText(DataType dataType) {
|
||||
int length = dataType.getLength();
|
||||
return new TextLine((length >= 0) ? Integer.toString(length) : " <i>Unsized</i>");
|
||||
if (length < 0) {
|
||||
return new TextLine(" <i>Unsized</i>");
|
||||
}
|
||||
if (dataType.isZeroLength()) {
|
||||
length = 0;
|
||||
}
|
||||
return new TextLine(Integer.toString(length));
|
||||
}
|
||||
|
||||
private static boolean canLinkDataType(DataType dt) {
|
||||
if (dt instanceof AbstractDataType) {
|
||||
return false;
|
||||
}
|
||||
UniversalID universalID = dt.getUniversalID();
|
||||
if (universalID == null) {
|
||||
return false;
|
||||
}
|
||||
DataTypeManager dtm = dt.getDataTypeManager();
|
||||
if (dtm == null) {
|
||||
return false;
|
||||
}
|
||||
return dtm.findDataTypeForID(dt.getUniversalID()) != null;
|
||||
}
|
||||
|
||||
protected static String generateTypeName(DataType dt, Color color, boolean trim) {
|
||||
|
||||
String[] pointerArraySplit = splitPointerArray(dt);
|
||||
if (pointerArraySplit != null) {
|
||||
DataType baseDt = DataTypeUtils.getNamedBaseDataType(dt);
|
||||
if (baseDt != null && canLinkDataType(baseDt)) {
|
||||
dt = baseDt; // ok to split for link
|
||||
}
|
||||
else {
|
||||
pointerArraySplit = null; // do not split/link
|
||||
}
|
||||
}
|
||||
|
||||
String type = dt.getName();
|
||||
if (trim) {
|
||||
type = truncateAsNecessary(type);
|
||||
}
|
||||
type = friendlyEncodeHTML(type);
|
||||
|
||||
if (pointerArraySplit == null && !canLinkDataType(dt)) {
|
||||
type = wrapStringInColor(type, color);
|
||||
return type;
|
||||
}
|
||||
|
||||
//
|
||||
// Markup the name with info for later hyperlink capability, as needed by the client
|
||||
//
|
||||
DataTypeUrl url = new DataTypeUrl(dt);
|
||||
String wrapped = HTMLUtilities.wrapWithLinkPlaceholder(type, url.toString());
|
||||
if (pointerArraySplit != null) {
|
||||
wrapped += friendlyEncodeHTML(pointerArraySplit[1], false);
|
||||
}
|
||||
wrapped = wrapStringInColor(wrapped, color);
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
private static String[] splitPointerArray(DataType dt) {
|
||||
|
||||
if (!(dt instanceof Pointer) && !(dt instanceof Array)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String name = dt.getName();
|
||||
|
||||
int lastIndex = -1;
|
||||
int index = name.length() - 1;
|
||||
while (true) {
|
||||
if (index <= 0) {
|
||||
// unexpected condition
|
||||
lastIndex = -1;
|
||||
break;
|
||||
}
|
||||
char c = name.charAt(index);
|
||||
if (c == '*' || c == '[') {
|
||||
lastIndex = index;
|
||||
}
|
||||
else if (c != ' ' && c != ']' && !Character.isDigit(c)) {
|
||||
break;
|
||||
}
|
||||
--index;
|
||||
}
|
||||
|
||||
if (lastIndex <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name.charAt(lastIndex - 1) == ' ') {
|
||||
--lastIndex;
|
||||
}
|
||||
|
||||
String[] split = new String[2];
|
||||
split[0] = name.substring(0, lastIndex).trim();
|
||||
split[1] = name.substring(lastIndex);
|
||||
return split;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
@ -66,25 +66,30 @@ public class PointerDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
String fullDescription = bits + " Pointer";
|
||||
|
||||
fullDescription = HTMLUtilities.friendlyEncodeHTML(fullDescription);
|
||||
buffer.append(FORWARD_SLASH).append(FORWARD_SLASH).append(HTML_SPACE);
|
||||
buffer.append(HTMLUtilities.friendlyEncodeHTML(pointer.getName()));
|
||||
buffer.append(BR);
|
||||
buffer.append(INDENT_OPEN);
|
||||
buffer.append(fullDescription);
|
||||
buffer.append(BR);
|
||||
buffer.append("Size: ").append((length >= 0) ? length : "default");
|
||||
addDataTypeLengthAndAlignment(pointer, buffer);
|
||||
buffer.append(INDENT_CLOSE);
|
||||
|
||||
buffer.append(BR).append(BR);
|
||||
buffer.append("Pointer Base Data Type: ").append(BR);
|
||||
buffer.append(BR);
|
||||
if (baseDataType instanceof BuiltInDataType) {
|
||||
String simpleName = baseDataType.getClass().getSimpleName();
|
||||
buffer.append(INDENT_OPEN);
|
||||
buffer.append(simpleName);
|
||||
addDataTypeLength(baseDataType, buffer);
|
||||
String simpleName = baseDataType.getDisplayName();
|
||||
buffer.append(TT_OPEN).append(simpleName).append(TT_CLOSE);
|
||||
buffer.append(BR).append(INDENT_OPEN);
|
||||
|
||||
String description = baseDataType.getDescription();
|
||||
if (!StringUtils.isBlank(description)) {
|
||||
String encodedDescription =
|
||||
HTMLUtilities.friendlyEncodeHTML(description);
|
||||
buffer.append(encodedDescription).append(BR);
|
||||
}
|
||||
addDataTypeLengthAndAlignment(baseDataType, buffer);
|
||||
buffer.append(INDENT_CLOSE);
|
||||
}
|
||||
else {
|
||||
buffer.append(INDENT_OPEN);
|
||||
|
||||
HTMLDataTypeRepresentation representation =
|
||||
ToolTipUtils.getHTMLRepresentation(baseDataType);
|
||||
String baseHTML = representation.getFullHTMLContentString();
|
||||
@ -95,10 +100,8 @@ public class PointerDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
buffer.append(baseHTML);
|
||||
|
||||
if (baseHTML.indexOf(LENGTH_PREFIX) < 0) {
|
||||
addDataTypeLength(baseDataType, buffer);
|
||||
addDataTypeLengthAndAlignment(baseDataType, buffer);
|
||||
}
|
||||
|
||||
buffer.append(INDENT_CLOSE);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
@ -118,7 +121,7 @@ public class PointerDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
|
||||
int length = pointer.getLength();
|
||||
description += BR;
|
||||
description += "Size: " + (length >= 0 ? length : "default");
|
||||
description += LENGTH_PREFIX + (length >= 0 ? length : "default");
|
||||
|
||||
return description;
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ package ghidra.app.util.html;
|
||||
import java.awt.Color;
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class TextLine implements ValidatableLine {
|
||||
|
||||
private String text;
|
||||
@ -50,6 +48,7 @@ public class TextLine implements ValidatableLine {
|
||||
return textColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(Color color) {
|
||||
this.textColor = color;
|
||||
}
|
||||
@ -75,8 +74,7 @@ public class TextLine implements ValidatableLine {
|
||||
@Override
|
||||
public boolean matches(ValidatableLine otherLine) {
|
||||
if (!(otherLine instanceof TextLine)) {
|
||||
throw new AssertException(
|
||||
"TextLine can only be matched against other " + "TextLine implementations.");
|
||||
return false;
|
||||
}
|
||||
TextLine textLine = (TextLine) otherLine;
|
||||
return text.equals(textLine.getText());
|
||||
@ -93,15 +91,9 @@ public class TextLine implements ValidatableLine {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(otherLine instanceof TextLine)) {
|
||||
throw new AssertException(
|
||||
"TextLine can only be matched against other " + "TextLine implementations.");
|
||||
}
|
||||
TextLine textLine = (TextLine) otherLine;
|
||||
|
||||
if (!matches(textLine)) {
|
||||
if (!matches(otherLine)) {
|
||||
setTextColor(invalidColor);
|
||||
textLine.setTextColor(invalidColor);
|
||||
otherLine.setTextColor(invalidColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@ package ghidra.app.util.html;
|
||||
import java.awt.Color;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.diff.DataTypeDiff;
|
||||
import ghidra.app.util.html.diff.DataTypeDiffBuilder;
|
||||
@ -25,7 +27,6 @@ import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
|
||||
|
||||
@ -45,7 +46,7 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
this.headerContent = headerLines;
|
||||
this.bodyContent = bodyLines;
|
||||
|
||||
List<ValidatableLine> trimmedHeaderContent = buildHeaderText(typeDef, true);
|
||||
List<ValidatableLine> trimmedHeaderContent = buildHeaderText(true);
|
||||
List<ValidatableLine> trimmedBodyContent = buildBodyText(getBaseDataType(), true);
|
||||
truncatedHtmlData =
|
||||
buildHTMLText(typeDef, warningLines, trimmedHeaderContent, trimmedBodyContent, true);
|
||||
@ -55,19 +56,36 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
this.typeDef = typeDef;
|
||||
|
||||
warningLines = buildWarnings();
|
||||
headerContent = buildHeaderText(typeDef, false);
|
||||
headerContent = buildHeaderText(false);
|
||||
bodyContent = buildBodyText(getBaseDataType(), false);
|
||||
|
||||
originalHTMLData = buildHTMLText(typeDef, warningLines, headerContent, bodyContent, false);
|
||||
|
||||
List<ValidatableLine> trimmedHeaderContent = buildHeaderText(typeDef, true);
|
||||
List<ValidatableLine> trimmedHeaderContent = buildHeaderText(true);
|
||||
List<ValidatableLine> trimmedBodyContent = buildBodyText(getBaseDataType(), true);
|
||||
truncatedHtmlData =
|
||||
buildHTMLText(typeDef, warningLines, trimmedHeaderContent, trimmedBodyContent, true);
|
||||
}
|
||||
|
||||
protected DataType getBaseDataType() {
|
||||
return getBaseDataType(typeDef);
|
||||
private DataType getBaseDataType() {
|
||||
DataType baseDataType = typeDef;
|
||||
while (!(baseDataType instanceof BuiltInDataType) && (baseDataType instanceof TypeDef)) {
|
||||
TypeDef td = (TypeDef) baseDataType;
|
||||
baseDataType = getBasePointerArrayDataType(td.getDataType());
|
||||
}
|
||||
return baseDataType;
|
||||
}
|
||||
|
||||
private static DataType getBasePointerArrayDataType(DataType dt) {
|
||||
while ((dt instanceof Pointer) || (dt instanceof Array)) {
|
||||
if (dt instanceof Pointer) {
|
||||
dt = ((Pointer) dt).getDataType();
|
||||
}
|
||||
else {
|
||||
dt = ((Array) dt).getDataType();
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
// overridden to return truncated text by default
|
||||
@ -82,14 +100,6 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
return truncatedHtmlData;
|
||||
}
|
||||
|
||||
private static DataType getBaseDataType(DataType dataType) {
|
||||
DataType basedataType = dataType;
|
||||
while (basedataType instanceof TypeDef) {
|
||||
basedataType = ((TypeDef) basedataType).getDataType();
|
||||
}
|
||||
return basedataType;
|
||||
}
|
||||
|
||||
protected List<String> buildWarnings() {
|
||||
DataType baseType = typeDef.getBaseDataType();
|
||||
if (!(baseType instanceof Composite) || !baseType.isZeroLength()) {
|
||||
@ -109,64 +119,84 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
return super.buildFooterText(dataType);
|
||||
}
|
||||
|
||||
protected List<ValidatableLine> buildHeaderText(DataType dataType, boolean trim) {
|
||||
DataType baseDataType = typeDef;
|
||||
private String getDataTypeNameHTML(TypeDef td, boolean trim) {
|
||||
String name = td.getName();
|
||||
if (trim) {
|
||||
name = truncateAsNecessary(name);
|
||||
}
|
||||
name = HTMLUtilities.friendlyEncodeHTML(name);
|
||||
|
||||
StringBuilder buffy = new StringBuilder(TT_OPEN);
|
||||
if (td.isAutoNamed()) {
|
||||
buffy.append("auto-typedef ");
|
||||
buffy.append(name);
|
||||
}
|
||||
else {
|
||||
buffy.append("typedef ");
|
||||
buffy.append(td != typeDef ? generateTypeName(td, null, trim) : name);
|
||||
buffy.append(" ");
|
||||
buffy.append(generateTypeName(td.getDataType(), null, trim));
|
||||
}
|
||||
buffy.append(TT_CLOSE).append(BR);
|
||||
return buffy.toString();
|
||||
}
|
||||
|
||||
protected List<ValidatableLine> buildHeaderText(boolean trim) {
|
||||
|
||||
DataType baseDataType = typeDef.getDataType();
|
||||
|
||||
List<ValidatableLine> lines = new ArrayList<>();
|
||||
while (baseDataType instanceof TypeDef) {
|
||||
lines.add(new TextLine(getDataTypeNameHTML(typeDef, trim)));
|
||||
|
||||
if (!typeDef.isAutoNamed()) {
|
||||
// Show modified default settings details (i.e., TypeDefSettingsDefinition)
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
String baseDtString = baseDataType.toString();
|
||||
if (trim) {
|
||||
baseDtString = StringUtilities.trimMiddle(baseDtString, ToolTipUtils.LINE_LENGTH);
|
||||
Settings defaultSettings = typeDef.getDefaultSettings();
|
||||
for (SettingsDefinition settingsDef : typeDef.getSettingsDefinitions()) {
|
||||
if (!(settingsDef instanceof TypeDefSettingsDefinition) ||
|
||||
!settingsDef.hasValue(defaultSettings)) {
|
||||
continue;
|
||||
}
|
||||
if (buffy.length() == 0) {
|
||||
buffy.append(INDENT_OPEN);
|
||||
}
|
||||
else {
|
||||
buffy.append(BR);
|
||||
}
|
||||
buffy.append(TT_OPEN)
|
||||
.append(settingsDef.getName())
|
||||
.append(": ")
|
||||
.append(settingsDef.getValueString(defaultSettings));
|
||||
buffy.append(TT_CLOSE);
|
||||
}
|
||||
String encodedBaseDt = HTMLUtilities.friendlyEncodeHTML(baseDtString);
|
||||
buffy.append(TT_OPEN).append(encodedBaseDt).append(TT_CLOSE).append(BR);
|
||||
lines.add(new TextLine(buffy.toString()));
|
||||
baseDataType = ((TypeDef) baseDataType).getDataType();
|
||||
while (baseDataType instanceof Pointer) {
|
||||
baseDataType = ((Pointer) baseDataType).getDataType();
|
||||
if (buffy.length() != 0) {
|
||||
buffy.append(INDENT_CLOSE);
|
||||
lines.add(new TextLine(buffy.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
baseDataType = typeDef.getBaseDataType();
|
||||
if (baseDataType instanceof Pointer || baseDataType instanceof Array) {
|
||||
String lengthAndAlignmentStr =
|
||||
addDataTypeLengthAndAlignment(typeDef, new StringBuilder()).toString();
|
||||
lines.add(new TextLine(INDENT_OPEN + lengthAndAlignmentStr + INDENT_CLOSE));
|
||||
}
|
||||
|
||||
// Show modified default settings details
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
Settings defaultSettings = typeDef.getDefaultSettings();
|
||||
HashSet<Class<?>> ignoredSettings = new HashSet<>();
|
||||
|
||||
for (SettingsDefinition settingsDef : typeDef.getSettingsDefinitions()) {
|
||||
if (!(settingsDef instanceof TypeDefSettingsDefinition) ||
|
||||
!settingsDef.hasValue(defaultSettings)) {
|
||||
continue;
|
||||
}
|
||||
if (settingsDef instanceof PointerTypeSettingsDefinition) {
|
||||
ignoredSettings.add(AddressSpaceSettingsDefinition.class);
|
||||
baseDataType = getBasePointerArrayDataType(baseDataType);
|
||||
boolean firstBaseTypedef = true;
|
||||
while (baseDataType instanceof TypeDef) {
|
||||
TypeDef td = (TypeDef) baseDataType;
|
||||
if (!td.isAutoNamed()) {
|
||||
String br = "";
|
||||
if (firstBaseTypedef) {
|
||||
br = "<BR>";
|
||||
firstBaseTypedef = false;
|
||||
}
|
||||
lines.add(new TextLine(br + getDataTypeNameHTML(td, trim)));
|
||||
}
|
||||
baseDataType = getBasePointerArrayDataType(td.getDataType());
|
||||
}
|
||||
|
||||
for (SettingsDefinition settingsDef : typeDef.getSettingsDefinitions()) {
|
||||
if (!(settingsDef instanceof TypeDefSettingsDefinition) ||
|
||||
!settingsDef.hasValue(defaultSettings)) {
|
||||
continue;
|
||||
}
|
||||
boolean ignored = ignoredSettings.contains(settingsDef.getClass());
|
||||
if (buffy.length() == 0) {
|
||||
buffy.append(INDENT_OPEN);
|
||||
}
|
||||
else {
|
||||
buffy.append(BR);
|
||||
}
|
||||
buffy.append(TT_OPEN)
|
||||
.append(settingsDef.getName())
|
||||
.append(": ")
|
||||
.append(settingsDef.getValueString(defaultSettings));
|
||||
if (ignored) {
|
||||
buffy.append(" (ignored)");
|
||||
}
|
||||
buffy.append(TT_CLOSE);
|
||||
}
|
||||
if (buffy.length() != 0) {
|
||||
buffy.append(INDENT_CLOSE);
|
||||
lines.add(new TextLine(buffy.toString()));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
@ -175,7 +205,7 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
if (baseDataType instanceof BuiltInDataType) {
|
||||
buildHTMLTextForBuiltIn(lines, baseDataType);
|
||||
}
|
||||
else {
|
||||
else if (baseDataType != null) {
|
||||
buildHTMLTextForBaseDataType(lines, baseDataType, trim);
|
||||
}
|
||||
return lines;
|
||||
@ -208,10 +238,6 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
|
||||
// body
|
||||
buffy.append(BR);
|
||||
if (typeDef.isPointer()) {
|
||||
buffy.append("Pointer-");
|
||||
}
|
||||
buffy.append("TypeDef Base Data Type: ").append(BR);
|
||||
|
||||
iterator = bodyLines.iterator();
|
||||
for (; iterator.hasNext();) {
|
||||
@ -227,33 +253,33 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
}
|
||||
|
||||
private static void buildHTMLTextForBuiltIn(List<ValidatableLine> lines,
|
||||
DataType basedataType) {
|
||||
lines.add(new TextLine(INDENT_OPEN));
|
||||
DataType baseDataType) {
|
||||
lines.add(new TextLine(TT_OPEN));
|
||||
String dataTypeDescriptionOrName = getDataTypeDescriptionOrName(basedataType);
|
||||
String encodedDescriptionOrName =
|
||||
HTMLUtilities.friendlyEncodeHTML(dataTypeDescriptionOrName);
|
||||
lines.add(new TextLine(encodedDescriptionOrName));
|
||||
String encodedName =
|
||||
HTMLUtilities.friendlyEncodeHTML(baseDataType.getDisplayName());
|
||||
lines.add(new TextLine(encodedName));
|
||||
lines.add(new TextLine(TT_CLOSE));
|
||||
StringBuilder buffy = addDataTypeLength(basedataType, new StringBuilder());
|
||||
lines.add(new TextLine(buffy.toString()));
|
||||
lines.add(new TextLine(BR));
|
||||
lines.add(new TextLine(INDENT_OPEN));
|
||||
|
||||
String description = baseDataType.getDescription();
|
||||
if (!StringUtils.isBlank(description)) {
|
||||
String encodedDescription =
|
||||
HTMLUtilities.friendlyEncodeHTML(description);
|
||||
lines.add(new TextLine(encodedDescription));
|
||||
lines.add(new TextLine(BR));
|
||||
}
|
||||
|
||||
lines.add(new TextLine(
|
||||
addDataTypeLengthAndAlignment(baseDataType, new StringBuilder()).toString()));
|
||||
lines.add(new TextLine(INDENT_CLOSE));
|
||||
}
|
||||
|
||||
private static String getDataTypeDescriptionOrName(DataType dataType) {
|
||||
String description = dataType.getDescription();
|
||||
if (description == null || description.length() == 0) {
|
||||
return dataType.getName();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
private static void buildHTMLTextForBaseDataType(List<ValidatableLine> lines,
|
||||
DataType basedataType, boolean trim) {
|
||||
lines.add(new TextLine(INDENT_OPEN));
|
||||
DataType baseDataType, boolean trim) {
|
||||
|
||||
HTMLDataTypeRepresentation baseRepresentation =
|
||||
ToolTipUtils.getHTMLRepresentation(basedataType);
|
||||
ToolTipUtils.getHTMLRepresentation(baseDataType);
|
||||
|
||||
String baseHTML = baseRepresentation.getFullHTMLContentString();
|
||||
if (trim) {
|
||||
@ -262,12 +288,11 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
|
||||
lines.add(new TextLine(baseHTML));
|
||||
|
||||
if (baseHTML.indexOf(LENGTH_PREFIX) < 0) {
|
||||
StringBuilder buffy = addDataTypeLength(basedataType, new StringBuilder());
|
||||
if (baseHTML.indexOf(LENGTH_PREFIX) < 0 && baseDataType.getLength() >= 0) {
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
addDataTypeLengthAndAlignment(baseDataType, buffy);
|
||||
lines.add(new TextLine(buffy.toString()));
|
||||
}
|
||||
|
||||
lines.add(new TextLine(INDENT_CLOSE));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -39,6 +38,12 @@ public interface ValidatableLine {
|
||||
|
||||
public String getText();
|
||||
|
||||
/**
|
||||
* Set color for all text.
|
||||
* @param color text color
|
||||
*/
|
||||
public void setTextColor(Color color);
|
||||
|
||||
/**
|
||||
* Sets the other line that this line is validated against. The other line may be a full,
|
||||
* partial, or no match at all.
|
||||
|
@ -20,7 +20,6 @@ import java.util.Objects;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class VariableTextLine implements ValidatableLine {
|
||||
|
||||
@ -117,8 +116,7 @@ public class VariableTextLine implements ValidatableLine {
|
||||
}
|
||||
|
||||
if (!(otherValidatableLine instanceof VariableTextLine)) {
|
||||
throw new AssertException("VariableTextLine can only be matched against other " +
|
||||
"VariableTextLine implementations.");
|
||||
return false;
|
||||
}
|
||||
VariableTextLine otherLine = (VariableTextLine) otherValidatableLine;
|
||||
|
||||
@ -146,8 +144,8 @@ public class VariableTextLine implements ValidatableLine {
|
||||
}
|
||||
|
||||
if (!(otherValidatableLine instanceof VariableTextLine)) {
|
||||
throw new AssertException("VariableTextLine can only be matched against other " +
|
||||
"VariableTextLine implementations.");
|
||||
otherValidatableLine.setTextColor(invalidColor);
|
||||
return;
|
||||
}
|
||||
|
||||
VariableTextLine otherLine = (VariableTextLine) otherValidatableLine;
|
||||
@ -162,6 +160,11 @@ public class VariableTextLine implements ValidatableLine {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(Color color) {
|
||||
setAllColors(color);
|
||||
}
|
||||
|
||||
void setAllColors(Color color) {
|
||||
variableTypeColor = color;
|
||||
variableNameColor = color;
|
||||
|
@ -813,19 +813,25 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest {
|
||||
|
||||
List<ValidatableLine> h1 = td1.headerContent;
|
||||
List<ValidatableLine> h2 = td2.headerContent;
|
||||
Assert.assertNotEquals("TypeDef diff should have different headers", h1, h2);
|
||||
Assert.assertNotEquals("Typedef diff should have different headers", h1, h2);
|
||||
|
||||
List<ValidatableLine> b1 = td1.bodyContent;
|
||||
List<ValidatableLine> b2 = td2.bodyContent;
|
||||
// List<ValidatableLine> b1 = td1.bodyContent;
|
||||
// List<ValidatableLine> b2 = td2.bodyContent;
|
||||
|
||||
// crude, but effective
|
||||
String s1 = b1.toString();
|
||||
String s2 = b2.toString();
|
||||
String s1 = h1.toString();
|
||||
String s2 = h2.toString();
|
||||
|
||||
String size1 = s1.replaceAll(".*Size: (\\d+).*", "$1");
|
||||
String size2 = s2.replaceAll(".*Size: (\\d+).*", "$1");
|
||||
Pattern p = Pattern.compile(".*Length: (\\d+).*");
|
||||
Matcher m1 = p.matcher(s1);
|
||||
assertTrue("Typedef length not found", m1.find());
|
||||
String size1 = m1.group(1);
|
||||
|
||||
Assert.assertNotEquals("TypeDef diff should have different Size values", size1, size2);
|
||||
Matcher m2 = p.matcher(s2);
|
||||
assertTrue("Typedef length not found", m2.find());
|
||||
String size2 = m2.group(1);
|
||||
|
||||
Assert.assertNotEquals("Typedef diff should have different Length values", size1, size2);
|
||||
}
|
||||
|
||||
private void assertTypeDefsSame(HTMLDataTypeRepresentation[] diff) {
|
||||
|
@ -526,7 +526,7 @@ public class HTMLUtilities {
|
||||
* This is useful when line wrapping to force wrapped lines to the left
|
||||
* @return the encoded HTML string
|
||||
*/
|
||||
private static String friendlyEncodeHTML(String text, boolean skipLeadingWhitespace) {
|
||||
public static String friendlyEncodeHTML(String text, boolean skipLeadingWhitespace) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user