Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge ResAttrDecoder into the AXmlResourceParser #3243

Merged
merged 1 commit into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@
import android.content.res.XmlResourceParser;
import android.util.TypedValue;
import brut.androlib.exceptions.AndrolibException;
import brut.androlib.exceptions.CantFindFrameworkResException;
import brut.androlib.exceptions.UndefinedResObjectException;
import brut.androlib.res.data.ResID;
import brut.androlib.res.data.ResResSpec;
import brut.androlib.res.data.ResTable;
import brut.androlib.res.data.arsc.ARSCHeader;
import brut.androlib.res.data.axml.NamespaceStack;
import brut.androlib.res.data.value.ResAttr;
import brut.androlib.res.data.value.ResScalarValue;
import brut.androlib.res.xml.ResXmlEncoders;
import brut.util.ExtCountingDataInput;
import com.google.common.io.LittleEndianDataInputStream;
Expand All @@ -44,20 +49,16 @@
public class AXmlResourceParser implements XmlResourceParser {

public AXmlResourceParser(ResTable resTable) {
mResTable = resTable;
resetEventInfo();
setAttrDecoder(new ResAttrDecoder(resTable));
}

public AndrolibException getFirstError() {
return mFirstError;
}

public ResAttrDecoder getAttrDecoder() {
return mAttrDecoder;
}

public void setAttrDecoder(ResAttrDecoder attrDecoder) {
mAttrDecoder = attrDecoder;
public ResTable getResTable() {
return mResTable;
}

public void open(InputStream stream) {
Expand Down Expand Up @@ -298,6 +299,19 @@ public String getAttributeNamespace(int index) {
return value;
}

public String decodeFromResourceId(int attrResId) throws AndrolibException {
if (attrResId != 0) {
try {
ResResSpec resResSpec = mResTable.getResSpec(attrResId);
if (resResSpec != null) {
return resResSpec.getName();
}
} catch (UndefinedResObjectException | CantFindFrameworkResException ignored) {}
}

return null;
}

private String getNonDefaultNamespaceUri(int offset) {
String prefix = mStringBlock.getString(mNamespaces.getPrefix(offset));
if (prefix != null) {
Expand Down Expand Up @@ -337,7 +351,7 @@ public String getAttributeName(int index) {
int resourceId = getAttributeNameResource(index);

try {
resourceMapValue = mAttrDecoder.decodeFromResourceId(resourceId);
resourceMapValue = decodeFromResourceId(resourceId);
} catch (AndrolibException ignored) {
resourceMapValue = null;
}
Expand Down Expand Up @@ -389,48 +403,56 @@ public String getAttributeValue(int index) {
int valueData = mAttributes[offset + ATTRIBUTE_IX_VALUE_DATA];
int valueRaw = mAttributes[offset + ATTRIBUTE_IX_VALUE_STRING];

if (mAttrDecoder != null) {
try {
String stringBlockValue = valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(mStringBlock.getString(valueRaw));
String resourceMapValue = null;

// Ensure we only track down obfuscated values for reference/attribute type values. Otherwise we might
// spam lookups against resource table for invalid ids.
if (valueType == TypedValue.TYPE_REFERENCE || valueType == TypedValue.TYPE_DYNAMIC_REFERENCE ||
valueType == TypedValue.TYPE_ATTRIBUTE || valueType == TypedValue.TYPE_DYNAMIC_ATTRIBUTE) {
resourceMapValue = mAttrDecoder.decodeFromResourceId(valueData);
}
String value = stringBlockValue;

if (stringBlockValue != null && resourceMapValue != null) {
int slashPos = stringBlockValue.lastIndexOf("/");
int colonPos = stringBlockValue.lastIndexOf(":");

// Handle a value with a format of "@yyy/xxx", but avoid "@yyy/zzz:xxx"
if (slashPos != -1) {
if (colonPos == -1) {
String type = stringBlockValue.substring(0, slashPos);
value = type + "/" + resourceMapValue;
}
} else if (! stringBlockValue.equals(resourceMapValue)) {
value = resourceMapValue;
try {
String stringBlockValue = valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(mStringBlock.getString(valueRaw));
String resourceMapValue = null;

// Ensure we only track down obfuscated values for reference/attribute type values. Otherwise we might
// spam lookups against resource table for invalid ids.
if (valueType == TypedValue.TYPE_REFERENCE || valueType == TypedValue.TYPE_DYNAMIC_REFERENCE ||
valueType == TypedValue.TYPE_ATTRIBUTE || valueType == TypedValue.TYPE_DYNAMIC_ATTRIBUTE) {
resourceMapValue = decodeFromResourceId(valueData);
}
String value = stringBlockValue;

if (stringBlockValue != null && resourceMapValue != null) {
int slashPos = stringBlockValue.lastIndexOf("/");
int colonPos = stringBlockValue.lastIndexOf(":");

// Handle a value with a format of "@yyy/xxx", but avoid "@yyy/zzz:xxx"
if (slashPos != -1) {
if (colonPos == -1) {
String type = stringBlockValue.substring(0, slashPos);
value = type + "/" + resourceMapValue;
}
} else if (! stringBlockValue.equals(resourceMapValue)) {
value = resourceMapValue;
}
}

// try to decode from resource table
int attrResId = getAttributeNameResource(index);
ResScalarValue resValue = mResTable.getCurrentResPackage()
.getValueFactory().factory(valueType, valueData, value);

String decoded = null;
if (attrResId > 0) {
try {
ResAttr attr = (ResAttr) mResTable.getResSpec(attrResId).getDefaultResource().getValue();

return mAttrDecoder.decode(
valueType,
valueData,
value,
getAttributeNameResource(index)
);
} catch (AndrolibException ex) {
setFirstError(ex);
LOGGER.log(Level.WARNING, String.format("Could not decode attr value, using undecoded value "
+ "instead: ns=%s, name=%s, value=0x%08x",
getAttributePrefix(index),
getAttributeName(index),
valueData), ex);
decoded = attr.convertToResXmlFormat(resValue);
} catch (UndefinedResObjectException | ClassCastException ignored) {}
}

return decoded != null ? decoded : resValue.encodeAsResXmlAttr();

} catch (AndrolibException ex) {
setFirstError(ex);
LOGGER.log(Level.WARNING, String.format("Could not decode attr value, using undecoded value "
+ "instead: ns=%s, name=%s, value=0x%08x",
getAttributePrefix(index),
getAttributeName(index),
valueData), ex);
}
return TypedValue.coerceToString(valueType, valueData);
}
Expand Down Expand Up @@ -801,7 +823,7 @@ private void setFirstError(AndrolibException error) {
}

private ExtCountingDataInput mIn;
private ResAttrDecoder mAttrDecoder;
private final ResTable mResTable;
private AndrolibException mFirstError;

private boolean isOperational = false;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import java.io.*;

public class XmlPullStreamDecoder implements ResStreamDecoder {
public XmlPullStreamDecoder(XmlPullParser parser,
public XmlPullStreamDecoder(AXmlResourceParser parser,
ExtXmlSerializer serializer) {
this.mParser = parser;
this.mSerial = serializer;
Expand All @@ -43,7 +43,7 @@ public void decode(InputStream in, OutputStream out)
try {
XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
final ResTable resTable = ((AXmlResourceParser) mParser).getAttrDecoder().getResTable();
final ResTable resTable = mParser.getResTable();

XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial, factory) {
boolean hideSdkInfo = false;
Expand Down Expand Up @@ -149,6 +149,6 @@ public void decodeManifest(InputStream in, OutputStream out)
decode(in, out);
}

private final XmlPullParser mParser;
private final AXmlResourceParser mParser;
private final ExtXmlSerializer mSerial;
}