mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-07 10:35:52 +01:00
Decoding XML files using pure-Java AXmlResourceParser instead of ResXmlStreamDecoder.
This commit is contained in:
parent
17380788c6
commit
a1d9766a90
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package brut.androlib.res;
|
package brut.androlib.res;
|
||||||
|
|
||||||
import brut.androlib.*;
|
import brut.androlib.AndrolibException;
|
||||||
import brut.androlib.res.data.*;
|
import brut.androlib.res.data.*;
|
||||||
import brut.androlib.res.data.value.ResFileValue;
|
import brut.androlib.res.data.value.ResFileValue;
|
||||||
import brut.androlib.res.data.value.ResXmlSerializable;
|
import brut.androlib.res.data.value.ResXmlSerializable;
|
||||||
@ -25,16 +25,11 @@ import brut.androlib.res.decoder.*;
|
|||||||
import brut.androlib.res.jni.JniPackage;
|
import brut.androlib.res.jni.JniPackage;
|
||||||
import brut.androlib.res.jni.JniPackageGroup;
|
import brut.androlib.res.jni.JniPackageGroup;
|
||||||
import brut.common.BrutException;
|
import brut.common.BrutException;
|
||||||
import brut.directory.Directory;
|
import brut.directory.*;
|
||||||
import brut.directory.DirectoryException;
|
import brut.util.*;
|
||||||
import brut.directory.FileDirectory;
|
import java.io.*;
|
||||||
import brut.directory.ZipRODirectory;
|
|
||||||
import brut.util.Jar;
|
|
||||||
import brut.util.OS;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
@ -53,9 +48,11 @@ final public class AndrolibResources {
|
|||||||
|
|
||||||
public void decode(ResTable resTable, File apkFile, File outDir)
|
public void decode(ResTable resTable, File apkFile, File outDir)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
ResXmlSerializer serial = getResXmlSerializer(resTable);
|
Duo<ResFileDecoder, ResAttrDecoder> duo = getResFileDecoder();
|
||||||
ResFileDecoder fileDecoder = getResFileDecoder(serial);
|
ResFileDecoder fileDecoder = duo.m1;
|
||||||
serial.setCurrentPackage(
|
ResAttrDecoder attrDecoder = duo.m2;
|
||||||
|
|
||||||
|
attrDecoder.setCurrentPackage(
|
||||||
resTable.listMainPackages().iterator().next());
|
resTable.listMainPackages().iterator().next());
|
||||||
|
|
||||||
Directory in, out;
|
Directory in, out;
|
||||||
@ -72,15 +69,16 @@ final public class AndrolibResources {
|
|||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResXmlSerializer xmlSerializer = getResXmlSerializer();
|
||||||
for (ResPackage pkg : resTable.listMainPackages()) {
|
for (ResPackage pkg : resTable.listMainPackages()) {
|
||||||
serial.setCurrentPackage(pkg);
|
attrDecoder.setCurrentPackage(pkg);
|
||||||
for (ResResource res : pkg.listFiles()) {
|
for (ResResource res : pkg.listFiles()) {
|
||||||
ResFileValue fileValue = (ResFileValue) res.getValue();
|
ResFileValue fileValue = (ResFileValue) res.getValue();
|
||||||
fileDecoder.decode(in, fileValue.getStrippedPath(),
|
fileDecoder.decode(in, fileValue.getStrippedPath(),
|
||||||
out, res.getFilePath());
|
out, res.getFilePath());
|
||||||
}
|
}
|
||||||
for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
|
for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
|
||||||
generateValuesFile(valuesFile, out, serial);
|
generateValuesFile(valuesFile, out, xmlSerializer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,27 +129,32 @@ final public class AndrolibResources {
|
|||||||
new ResSmaliUpdater().updateResIDs(resTable, smaliDir);
|
new ResSmaliUpdater().updateResIDs(resTable, smaliDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResFileDecoder getResFileDecoder(ResXmlSerializer serializer) {
|
public Duo<ResFileDecoder, ResAttrDecoder> getResFileDecoder() {
|
||||||
ResStreamDecoderContainer decoders =
|
ResStreamDecoderContainer decoders =
|
||||||
new ResStreamDecoderContainer();
|
new ResStreamDecoderContainer();
|
||||||
decoders.setDecoder("raw", new ResRawStreamDecoder());
|
decoders.setDecoder("raw", new ResRawStreamDecoder());
|
||||||
|
|
||||||
|
ResAttrDecoder attrDecoder = new ResAttrDecoder();
|
||||||
|
AXmlResourceParser axmlParser = new AXmlResourceParser();
|
||||||
|
axmlParser.setAttrDecoder(attrDecoder);
|
||||||
decoders.setDecoder("xml",
|
decoders.setDecoder("xml",
|
||||||
new ResXmlStreamDecoder(serializer));
|
new XmlPullStreamDecoder(axmlParser, getResXmlSerializer()));
|
||||||
return new ResFileDecoder(decoders);
|
|
||||||
|
return new Duo<ResFileDecoder, ResAttrDecoder>(
|
||||||
|
new ResFileDecoder(decoders), attrDecoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResXmlSerializer getResXmlSerializer(ResTable resTable) {
|
public ResXmlSerializer getResXmlSerializer() {
|
||||||
ResXmlSerializer serial = new ResXmlSerializer();
|
ResXmlSerializer serial = new ResXmlSerializer();
|
||||||
serial.setProperty(serial.PROPERTY_SERIALIZER_INDENTATION, " ");
|
serial.setProperty(serial.PROPERTY_SERIALIZER_INDENTATION, " ");
|
||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
|
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
|
||||||
ResXmlSerializer serial) throws AndrolibException {
|
XmlSerializer serial) throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
OutputStream outStream = out.getFileOutput(valuesFile.getPath());
|
OutputStream outStream = out.getFileOutput(valuesFile.getPath());
|
||||||
serial.setOutput((outStream), null);
|
serial.setOutput((outStream), null);
|
||||||
serial.setDecodingEnabled(false);
|
|
||||||
serial.startDocument(null, null);
|
serial.startDocument(null, null);
|
||||||
serial.startTag(null, "resources");
|
serial.startTag(null, "resources");
|
||||||
|
|
||||||
|
@ -17,102 +17,17 @@
|
|||||||
|
|
||||||
package brut.androlib.res.decoder;
|
package brut.androlib.res.decoder;
|
||||||
|
|
||||||
import brut.androlib.*;
|
|
||||||
import brut.androlib.err.UndefinedResObject;
|
|
||||||
import brut.androlib.res.AndrolibResources;
|
|
||||||
import brut.androlib.res.data.ResPackage;
|
|
||||||
import brut.androlib.res.data.value.ResAttr;
|
|
||||||
import brut.androlib.res.data.value.ResScalarValue;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.xmlpull.mxp1_serializer.MXSerializer;
|
import org.xmlpull.mxp1_serializer.MXSerializer;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ResXmlSerializer extends MXSerializer {
|
public class ResXmlSerializer extends MXSerializer {
|
||||||
private final static String RES_NAMESPACE =
|
|
||||||
"http://schemas.android.com/apk/res/android";
|
|
||||||
|
|
||||||
private ResPackage mCurrentPackage;
|
|
||||||
private boolean mDecodingEnabled = true;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public XmlSerializer attribute(String namespace, String name, String value)
|
|
||||||
throws IOException, IllegalArgumentException, IllegalStateException
|
|
||||||
{
|
|
||||||
if (! mDecodingEnabled) {
|
|
||||||
return super.attribute(namespace, name, value);
|
|
||||||
}
|
|
||||||
String origVal = value;
|
|
||||||
|
|
||||||
try {
|
|
||||||
ResScalarValue resValue =
|
|
||||||
mCurrentPackage.getValueFactory().factory(value);
|
|
||||||
value = null;
|
|
||||||
|
|
||||||
if (namespace != null && ! namespace.isEmpty()) {
|
|
||||||
String pkgName = RES_NAMESPACE.equals(namespace) ?
|
|
||||||
"android" : mCurrentPackage.getName();
|
|
||||||
try {
|
|
||||||
ResAttr attr = (ResAttr) mCurrentPackage.getResTable()
|
|
||||||
.getValue(pkgName, "attr", name);
|
|
||||||
value = attr.convertToResXmlFormat(resValue);
|
|
||||||
} catch (UndefinedResObject ex) {
|
|
||||||
System.err.println(String.format(
|
|
||||||
"warning: udefined attr when decoding: " +
|
|
||||||
"ns=%s, name=%s, value=%s",
|
|
||||||
namespace, name, origVal));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == null) {
|
|
||||||
value = resValue.toResXmlFormat();
|
|
||||||
}
|
|
||||||
} catch (AndrolibException ex) {
|
|
||||||
throw new IllegalArgumentException(String.format(
|
|
||||||
"could not decode attribute: ns=%s, name=%s, value=%s",
|
|
||||||
namespace, name, origVal), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == null) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.attribute(namespace, name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public XmlSerializer text(String text) throws IOException {
|
|
||||||
if (mDecodingEnabled) {
|
|
||||||
text = AndrolibResources.escapeForResXml(text);
|
|
||||||
}
|
|
||||||
return super.text(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public XmlSerializer text(char[] buf, int start, int len) throws IOException {
|
|
||||||
if (mDecodingEnabled) {
|
|
||||||
return this.text(new String(buf, start, len));
|
|
||||||
}
|
|
||||||
return super.text(buf, start, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startDocument(String encoding, Boolean standalone) throws
|
public void startDocument(String encoding, Boolean standalone) throws
|
||||||
IOException, IllegalArgumentException, IllegalStateException {
|
IOException, IllegalArgumentException, IllegalStateException {
|
||||||
super.startDocument(encoding != null ? encoding : "UTF-8", standalone);
|
super.startDocument(encoding != null ? encoding : "UTF-8", standalone);
|
||||||
super.out.write("\n");
|
super.out.write("\n");
|
||||||
super.setPrefix("android", RES_NAMESPACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentPackage(ResPackage package_) {
|
|
||||||
mCurrentPackage = package_;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean setDecodingEnabled(boolean escapeRefs) {
|
|
||||||
boolean oldVal = mDecodingEnabled;
|
|
||||||
this.mDecodingEnabled = escapeRefs;
|
|
||||||
return oldVal;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public class ResXmlStreamDecoder implements ResStreamDecoder {
|
|||||||
XmlSerializerWrapper ser =
|
XmlSerializerWrapper ser =
|
||||||
getXmlWrapperFactory().newSerializerWrapper(mSerializer);
|
getXmlWrapperFactory().newSerializerWrapper(mSerializer);
|
||||||
ser.setOutput(out, null);
|
ser.setOutput(out, null);
|
||||||
mSerializer.setDecodingEnabled(true);
|
// mSerializer.setDecodingEnabled(true);
|
||||||
|
|
||||||
while (par.nextToken() != XmlPullParser.END_DOCUMENT) {
|
while (par.nextToken() != XmlPullParser.END_DOCUMENT) {
|
||||||
ser.event(par);
|
ser.event(par);
|
||||||
|
Loading…
Reference in New Issue
Block a user