Decoding XML files using pure-Java AXmlResourceParser instead of ResXmlStreamDecoder.

This commit is contained in:
Ryszard Wiśniewski 2010-03-23 21:07:07 +01:00
parent 17380788c6
commit a1d9766a90
3 changed files with 25 additions and 107 deletions

View File

@ -17,7 +17,7 @@
package brut.androlib.res;
import brut.androlib.*;
import brut.androlib.AndrolibException;
import brut.androlib.res.data.*;
import brut.androlib.res.data.value.ResFileValue;
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.JniPackageGroup;
import brut.common.BrutException;
import brut.directory.Directory;
import brut.directory.DirectoryException;
import brut.directory.FileDirectory;
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 brut.directory.*;
import brut.util.*;
import java.io.*;
import java.util.Arrays;
import org.xmlpull.v1.XmlSerializer;
/**
* @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)
throws AndrolibException {
ResXmlSerializer serial = getResXmlSerializer(resTable);
ResFileDecoder fileDecoder = getResFileDecoder(serial);
serial.setCurrentPackage(
Duo<ResFileDecoder, ResAttrDecoder> duo = getResFileDecoder();
ResFileDecoder fileDecoder = duo.m1;
ResAttrDecoder attrDecoder = duo.m2;
attrDecoder.setCurrentPackage(
resTable.listMainPackages().iterator().next());
Directory in, out;
@ -72,15 +69,16 @@ final public class AndrolibResources {
throw new AndrolibException(ex);
}
ResXmlSerializer xmlSerializer = getResXmlSerializer();
for (ResPackage pkg : resTable.listMainPackages()) {
serial.setCurrentPackage(pkg);
attrDecoder.setCurrentPackage(pkg);
for (ResResource res : pkg.listFiles()) {
ResFileValue fileValue = (ResFileValue) res.getValue();
fileDecoder.decode(in, fileValue.getStrippedPath(),
out, res.getFilePath());
}
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);
}
public ResFileDecoder getResFileDecoder(ResXmlSerializer serializer) {
public Duo<ResFileDecoder, ResAttrDecoder> getResFileDecoder() {
ResStreamDecoderContainer decoders =
new ResStreamDecoderContainer();
decoders.setDecoder("raw", new ResRawStreamDecoder());
ResAttrDecoder attrDecoder = new ResAttrDecoder();
AXmlResourceParser axmlParser = new AXmlResourceParser();
axmlParser.setAttrDecoder(attrDecoder);
decoders.setDecoder("xml",
new ResXmlStreamDecoder(serializer));
return new ResFileDecoder(decoders);
new XmlPullStreamDecoder(axmlParser, getResXmlSerializer()));
return new Duo<ResFileDecoder, ResAttrDecoder>(
new ResFileDecoder(decoders), attrDecoder);
}
public ResXmlSerializer getResXmlSerializer(ResTable resTable) {
public ResXmlSerializer getResXmlSerializer() {
ResXmlSerializer serial = new ResXmlSerializer();
serial.setProperty(serial.PROPERTY_SERIALIZER_INDENTATION, " ");
return serial;
}
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
ResXmlSerializer serial) throws AndrolibException {
XmlSerializer serial) throws AndrolibException {
try {
OutputStream outStream = out.getFileOutput(valuesFile.getPath());
serial.setOutput((outStream), null);
serial.setDecodingEnabled(false);
serial.startDocument(null, null);
serial.startTag(null, "resources");

View File

@ -17,102 +17,17 @@
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 org.xmlpull.mxp1_serializer.MXSerializer;
import org.xmlpull.v1.XmlSerializer;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
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
public void startDocument(String encoding, Boolean standalone) throws
IOException, IllegalArgumentException, IllegalStateException {
super.startDocument(encoding != null ? encoding : "UTF-8", standalone);
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;
}
}

View File

@ -42,7 +42,7 @@ public class ResXmlStreamDecoder implements ResStreamDecoder {
XmlSerializerWrapper ser =
getXmlWrapperFactory().newSerializerWrapper(mSerializer);
ser.setOutput(out, null);
mSerializer.setDecodingEnabled(true);
// mSerializer.setDecodingEnabled(true);
while (par.nextToken() != XmlPullParser.END_DOCUMENT) {
ser.event(par);