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; 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");

View File

@ -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;
} }
} }

View File

@ -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);