Merge ResAttrDecoder into the AXmlResourceParser (#3243)

This commit is contained in:
sv99 2023-08-02 01:43:15 +03:00 committed by GitHub
parent 9d7d58016e
commit 0a354a9d97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 126 deletions

View File

@ -19,10 +19,15 @@ package brut.androlib.res.decoder;
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;
@ -44,20 +49,16 @@ import java.util.logging.Logger;
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) {
@ -298,6 +299,19 @@ public class AXmlResourceParser implements XmlResourceParser {
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) {
@ -337,7 +351,7 @@ public class AXmlResourceParser implements XmlResourceParser {
int resourceId = getAttributeNameResource(index);
try {
resourceMapValue = mAttrDecoder.decodeFromResourceId(resourceId);
resourceMapValue = decodeFromResourceId(resourceId);
} catch (AndrolibException ignored) {
resourceMapValue = null;
}
@ -389,48 +403,56 @@ public class AXmlResourceParser implements XmlResourceParser {
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;
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;
}
}
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);
// 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();
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);
}
@ -801,7 +823,7 @@ public class AXmlResourceParser implements XmlResourceParser {
}
private ExtCountingDataInput mIn;
private ResAttrDecoder mAttrDecoder;
private final ResTable mResTable;
private AndrolibException mFirstError;
private boolean isOperational = false;

View File

@ -1,74 +0,0 @@
/*
* Copyright (C) 2010 Ryszard Wiśniewski <brut.alll@gmail.com>
* Copyright (C) 2010 Connor Tumbleson <connor.tumbleson@gmail.com>
*
* 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
*
* https://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 brut.androlib.res.decoder;
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.value.ResAttr;
import brut.androlib.res.data.value.ResScalarValue;
public class ResAttrDecoder {
public ResAttrDecoder(ResTable resTable) {
mResTable = resTable;
}
public String decode(int type, int value, String rawValue, int attrResId) throws AndrolibException {
ResScalarValue resValue = mResTable.getCurrentResPackage().getValueFactory().factory(type, value, rawValue);
String decoded = null;
if (attrResId > 0) {
try {
ResAttr attr = (ResAttr) mResTable.getResSpec(attrResId).getDefaultResource().getValue();
decoded = attr.convertToResXmlFormat(resValue);
} catch (UndefinedResObjectException | ClassCastException ignored) {}
}
return decoded != null ? decoded : resValue.encodeAsResXmlAttr();
}
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;
}
public ResTable getResTable() throws AndrolibException {
if (mResTable == null) {
throw new AndrolibException("Res Table not set");
}
return mResTable;
}
public void setResTable(ResTable resTable) {
mResTable = resTable;
}
private ResTable mResTable;
}

View File

@ -31,7 +31,7 @@ import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;
import java.io.*;
public class XmlPullStreamDecoder implements ResStreamDecoder {
public XmlPullStreamDecoder(XmlPullParser parser,
public XmlPullStreamDecoder(AXmlResourceParser parser,
ExtXmlSerializer serializer) {
this.mParser = parser;
this.mSerial = serializer;
@ -43,7 +43,7 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
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;
@ -149,6 +149,6 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
decode(in, out);
}
private final XmlPullParser mParser;
private final AXmlResourceParser mParser;
private final ExtXmlSerializer mSerial;
}