mirror of
https://github.com/iBotPeaches/Apktool.git
synced 2024-11-23 04:30:04 +00:00
refactor: clean up external pull parser and introduce brut.j.xml (#3709)
Some checks failed
Analyze / Analyze (push) Has been cancelled
CI / analyze-mac-aapt (aapt2_64) (push) Has been cancelled
CI / analyze-mac-aapt (aapt_64) (push) Has been cancelled
CI / analyze-linux-aapt (aapt) (push) Has been cancelled
CI / analyze-linux-aapt (aapt2) (push) Has been cancelled
CI / analyze-linux-aapt (aapt2_64) (push) Has been cancelled
CI / analyze-linux-aapt (aapt_64) (push) Has been cancelled
CI / analyze-windows-aapt (aapt.exe) (push) Has been cancelled
CI / analyze-windows-aapt (aapt2.exe) (push) Has been cancelled
CI / analyze-windows-aapt (aapt2_64.exe) (push) Has been cancelled
CI / analyze-windows-aapt (aapt_64.exe) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (11, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (11, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (11, windows-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (17, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (17, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (17, windows-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (21, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (21, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (21, windows-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (8, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (8, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (8, windows-latest) (push) Has been cancelled
CI / Build apktool.jar (push) Has been cancelled
Some checks failed
Analyze / Analyze (push) Has been cancelled
CI / analyze-mac-aapt (aapt2_64) (push) Has been cancelled
CI / analyze-mac-aapt (aapt_64) (push) Has been cancelled
CI / analyze-linux-aapt (aapt) (push) Has been cancelled
CI / analyze-linux-aapt (aapt2) (push) Has been cancelled
CI / analyze-linux-aapt (aapt2_64) (push) Has been cancelled
CI / analyze-linux-aapt (aapt_64) (push) Has been cancelled
CI / analyze-windows-aapt (aapt.exe) (push) Has been cancelled
CI / analyze-windows-aapt (aapt2.exe) (push) Has been cancelled
CI / analyze-windows-aapt (aapt2_64.exe) (push) Has been cancelled
CI / analyze-windows-aapt (aapt_64.exe) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (11, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (11, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (11, windows-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (17, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (17, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (17, windows-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (21, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (21, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (21, windows-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (8, macOS-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (8, ubuntu-latest) (push) Has been cancelled
CI / Build/Test (JDK ${{ matrix.java }}, ${{ matrix.os }}) (8, windows-latest) (push) Has been cancelled
CI / Build apktool.jar (push) Has been cancelled
* refactor: clean up external pull parser and introduce brut.j.xml We have no need for an XML pull parser in the project, it was only used for testing, which is now done with XPath. The external xpp3 library from org.ogce is obsolete and has the issue of including javax.xml.namespace.QName which conflicts with the JRE implementation that exists for a very long time now. This makes direct usages of QName produce very obscure NPEs that took me hours to figure out. This patch will allow further optimization that is WIP. The external library was replaced by the basic xmlpull API. The MXSerializer has been cleaned and the features used by apktool have been integrated into the custom implementation, now part of a separate module called brut.j.xml. Writing has been optimized by buffering write operations, inspired by KXmlSerializer used by Android itself. A class XmlPullUtils also written that allows copying from a XmlPullParser into a XmlSerializer with or without an EventHandler. We use it for AndroidManifestPullStreamDecoder (with EventHandler, to allow omitting the uses-sdk tag), and for ResXmlPullStreamDecoder (direct copy, without EventHandler). saveDocument in ResXmlPatcher was tweaked to output proper output - a new line after declaration and a new line after root element's end tag. TL;DR mostly behind the scene refactor, no end user changes.
This commit is contained in:
parent
7033f4ee2f
commit
b49e77087d
3
brut.apktool/apktool-cli/proguard-rules.pro
vendored
3
brut.apktool/apktool-cli/proguard-rules.pro
vendored
@ -6,9 +6,6 @@
|
|||||||
static ** valueOf(java.lang.String);
|
static ** valueOf(java.lang.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
# https://github.com/iBotPeaches/Apktool/issues/3602#issuecomment-2117317880
|
|
||||||
-dontwarn org.xmlpull.mxp1**
|
|
||||||
|
|
||||||
# https://github.com/iBotPeaches/Apktool/pull/3670#issuecomment-2296326878
|
# https://github.com/iBotPeaches/Apktool/pull/3670#issuecomment-2296326878
|
||||||
-dontwarn com.google.j2objc.annotations.Weak
|
-dontwarn com.google.j2objc.annotations.Weak
|
||||||
-dontwarn com.google.j2objc.annotations.RetainedWith
|
-dontwarn com.google.j2objc.annotations.RetainedWith
|
||||||
|
@ -25,13 +25,13 @@ tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":brut.j.dir"))
|
|
||||||
api(project(":brut.j.util"))
|
|
||||||
api(project(":brut.j.common"))
|
api(project(":brut.j.common"))
|
||||||
|
api(project(":brut.j.util"))
|
||||||
|
api(project(":brut.j.dir"))
|
||||||
|
api(project(":brut.j.xml"))
|
||||||
|
|
||||||
implementation(libs.baksmali)
|
implementation(libs.baksmali)
|
||||||
implementation(libs.smali)
|
implementation(libs.smali)
|
||||||
implementation(libs.xmlpull)
|
|
||||||
implementation(libs.guava)
|
implementation(libs.guava)
|
||||||
implementation(libs.commons.lang3)
|
implementation(libs.commons.lang3)
|
||||||
implementation(libs.commons.io)
|
implementation(libs.commons.io)
|
||||||
|
@ -21,13 +21,12 @@ import brut.androlib.apk.ApkInfo;
|
|||||||
import brut.androlib.exceptions.AndrolibException;
|
import brut.androlib.exceptions.AndrolibException;
|
||||||
import brut.androlib.res.data.*;
|
import brut.androlib.res.data.*;
|
||||||
import brut.androlib.res.decoder.*;
|
import brut.androlib.res.decoder.*;
|
||||||
import brut.androlib.res.util.ExtMXSerializer;
|
|
||||||
import brut.androlib.res.util.ExtXmlSerializer;
|
|
||||||
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
import brut.androlib.res.xml.ResValuesXmlSerializable;
|
||||||
import brut.androlib.res.xml.ResXmlPatcher;
|
import brut.androlib.res.xml.ResXmlPatcher;
|
||||||
import brut.directory.Directory;
|
import brut.directory.Directory;
|
||||||
import brut.directory.DirectoryException;
|
import brut.directory.DirectoryException;
|
||||||
import brut.directory.FileDirectory;
|
import brut.directory.FileDirectory;
|
||||||
|
import brut.xmlpull.MXSerializer;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
@ -75,7 +74,8 @@ public class ResourcesDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AXmlResourceParser axmlParser = new AndroidManifestResourceParser(mResTable);
|
AXmlResourceParser axmlParser = new AndroidManifestResourceParser(mResTable);
|
||||||
ResStreamDecoder fileDecoder = new AndroidManifestPullStreamDecoder(axmlParser, getResXmlSerializer());
|
XmlSerializer xmlSerializer = newXmlSerializer();
|
||||||
|
ResStreamDecoder fileDecoder = new AndroidManifestPullStreamDecoder(axmlParser, xmlSerializer);
|
||||||
|
|
||||||
Directory inApk, out;
|
Directory inApk, out;
|
||||||
InputStream inputStream = null;
|
InputStream inputStream = null;
|
||||||
@ -157,7 +157,8 @@ public class ResourcesDecoder {
|
|||||||
decoders.setDecoder("9patch", new Res9patchStreamDecoder());
|
decoders.setDecoder("9patch", new Res9patchStreamDecoder());
|
||||||
|
|
||||||
AXmlResourceParser axmlParser = new AXmlResourceParser(mResTable);
|
AXmlResourceParser axmlParser = new AXmlResourceParser(mResTable);
|
||||||
decoders.setDecoder("xml", new ResXmlPullStreamDecoder(axmlParser, getResXmlSerializer()));
|
XmlSerializer xmlSerializer = newXmlSerializer();
|
||||||
|
decoders.setDecoder("xml", new ResXmlPullStreamDecoder(axmlParser, xmlSerializer));
|
||||||
|
|
||||||
ResFileDecoder fileDecoder = new ResFileDecoder(decoders);
|
ResFileDecoder fileDecoder = new ResFileDecoder(decoders);
|
||||||
Directory in, out, outRes;
|
Directory in, out, outRes;
|
||||||
@ -170,7 +171,6 @@ public class ResourcesDecoder {
|
|||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtMXSerializer xmlSerializer = getResXmlSerializer();
|
|
||||||
for (ResPackage pkg : mResTable.listMainPackages()) {
|
for (ResPackage pkg : mResTable.listMainPackages()) {
|
||||||
|
|
||||||
LOGGER.info("Decoding file-resources...");
|
LOGGER.info("Decoding file-resources...");
|
||||||
@ -191,20 +191,24 @@ public class ResourcesDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExtMXSerializer getResXmlSerializer() {
|
private XmlSerializer newXmlSerializer() throws AndrolibException {
|
||||||
ExtMXSerializer serial = new ExtMXSerializer();
|
try {
|
||||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, " ");
|
XmlSerializer serial = new MXSerializer();
|
||||||
serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, System.getProperty("line.separator"));
|
serial.setFeature(MXSerializer.FEATURE_ATTR_VALUE_NO_ESCAPE, true);
|
||||||
serial.setProperty(ExtXmlSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
|
serial.setProperty(MXSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8");
|
||||||
serial.setDisabledAttrEscape(true);
|
serial.setProperty(MXSerializer.PROPERTY_INDENTATION, " ");
|
||||||
return serial;
|
serial.setProperty(MXSerializer.PROPERTY_LINE_SEPARATOR, System.getProperty("line.separator"));
|
||||||
|
return serial;
|
||||||
|
} catch (IllegalArgumentException | IllegalStateException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
|
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
|
||||||
ExtXmlSerializer 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.startDocument(null, null);
|
serial.startDocument(null, null);
|
||||||
serial.startTag(null, "resources");
|
serial.startTag(null, "resources");
|
||||||
|
|
||||||
@ -216,7 +220,6 @@ public class ResourcesDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serial.endTag(null, "resources");
|
serial.endTag(null, "resources");
|
||||||
serial.newLine();
|
|
||||||
serial.endDocument();
|
serial.endDocument();
|
||||||
serial.flush();
|
serial.flush();
|
||||||
outStream.close();
|
outStream.close();
|
||||||
|
@ -611,12 +611,12 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getFeature(String feature) {
|
public boolean getFeature(String name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFeature(String name, boolean value) throws XmlPullParserException {
|
public void setFeature(String name, boolean state) throws XmlPullParserException {
|
||||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,122 +20,28 @@ import brut.androlib.exceptions.AndrolibException;
|
|||||||
import brut.androlib.exceptions.AXmlDecodingException;
|
import brut.androlib.exceptions.AXmlDecodingException;
|
||||||
import brut.androlib.exceptions.RawXmlEncounteredException;
|
import brut.androlib.exceptions.RawXmlEncounteredException;
|
||||||
import brut.androlib.res.data.ResTable;
|
import brut.androlib.res.data.ResTable;
|
||||||
import brut.androlib.res.util.ExtXmlSerializer;
|
import brut.xmlpull.XmlPullUtils;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
import org.xmlpull.v1.wrapper.XmlPullParserWrapper;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
import org.xmlpull.v1.wrapper.XmlPullWrapperFactory;
|
|
||||||
import org.xmlpull.v1.wrapper.XmlSerializerWrapper;
|
|
||||||
import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
public class AndroidManifestPullStreamDecoder implements ResStreamDecoder {
|
public class AndroidManifestPullStreamDecoder implements ResStreamDecoder {
|
||||||
public AndroidManifestPullStreamDecoder(AXmlResourceParser parser,
|
private final AXmlResourceParser mParser;
|
||||||
ExtXmlSerializer serializer) {
|
private final XmlSerializer mSerial;
|
||||||
this.mParser = parser;
|
|
||||||
this.mSerial = serializer;
|
public AndroidManifestPullStreamDecoder(AXmlResourceParser parser, XmlSerializer serial) {
|
||||||
|
mParser = parser;
|
||||||
|
mSerial = serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(InputStream in, OutputStream out)
|
public void decode(InputStream in, OutputStream out) throws AndrolibException {
|
||||||
throws AndrolibException {
|
|
||||||
try {
|
try {
|
||||||
XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
|
mParser.setInput(in, null);
|
||||||
XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
|
mSerial.setOutput(out, null);
|
||||||
final ResTable resTable = mParser.getResTable();
|
XmlPullUtils.copy(mParser, mSerial, new EventHandler(mParser.getResTable()));
|
||||||
|
|
||||||
XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial, factory) {
|
|
||||||
final boolean hideSdkInfo = !resTable.getAnalysisMode();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void event(XmlPullParser pp)
|
|
||||||
throws XmlPullParserException, IOException {
|
|
||||||
int type = pp.getEventType();
|
|
||||||
|
|
||||||
if (type == XmlPullParser.START_TAG) {
|
|
||||||
if ("manifest".equals(pp.getName())) {
|
|
||||||
try {
|
|
||||||
parseManifest(pp);
|
|
||||||
} catch (AndrolibException ignored) {}
|
|
||||||
} else if ("uses-sdk".equals(pp.getName())) {
|
|
||||||
try {
|
|
||||||
parseUsesSdk(pp);
|
|
||||||
} catch (AndrolibException ignored) {}
|
|
||||||
if (hideSdkInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (type == XmlPullParser.END_TAG
|
|
||||||
&& "uses-sdk".equals(pp.getName())) {
|
|
||||||
if (hideSdkInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.event(pp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseManifest(XmlPullParser pp)
|
|
||||||
throws AndrolibException {
|
|
||||||
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
|
||||||
String ns = pp.getAttributeNamespace(i);
|
|
||||||
String name = pp.getAttributeName(i);
|
|
||||||
String value = pp.getAttributeValue(i);
|
|
||||||
|
|
||||||
if (value.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ns.isEmpty()) {
|
|
||||||
if (name.equals("package")) {
|
|
||||||
resTable.setPackageRenamed(value);
|
|
||||||
}
|
|
||||||
} else if (ns.equals(AXmlResourceParser.ANDROID_RES_NS)) {
|
|
||||||
switch (name) {
|
|
||||||
case "versionCode":
|
|
||||||
resTable.setVersionCode(value);
|
|
||||||
break;
|
|
||||||
case "versionName":
|
|
||||||
resTable.setVersionName(value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseUsesSdk(XmlPullParser pp)
|
|
||||||
throws AndrolibException {
|
|
||||||
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
|
||||||
String ns = pp.getAttributeNamespace(i);
|
|
||||||
String name = pp.getAttributeName(i);
|
|
||||||
String value = pp.getAttributeValue(i);
|
|
||||||
|
|
||||||
if (value.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ns.equals(AXmlResourceParser.ANDROID_RES_NS)) {
|
|
||||||
switch (name) {
|
|
||||||
case "minSdkVersion":
|
|
||||||
case "targetSdkVersion":
|
|
||||||
case "maxSdkVersion":
|
|
||||||
case "compileSdkVersion":
|
|
||||||
resTable.addSdkInfo(name, value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
par.setInput(in, null);
|
|
||||||
ser.setOutput(out, null);
|
|
||||||
|
|
||||||
while (par.nextToken() != XmlPullParser.END_DOCUMENT) {
|
|
||||||
ser.event(par);
|
|
||||||
}
|
|
||||||
ser.flush();
|
|
||||||
} catch (XmlPullParserException ex) {
|
} catch (XmlPullParserException ex) {
|
||||||
throw new AXmlDecodingException("Could not decode XML", ex);
|
throw new AXmlDecodingException("Could not decode XML", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
@ -143,6 +49,90 @@ public class AndroidManifestPullStreamDecoder implements ResStreamDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AXmlResourceParser mParser;
|
private static class EventHandler implements XmlPullUtils.EventHandler {
|
||||||
private final ExtXmlSerializer mSerial;
|
private final ResTable mResTable;
|
||||||
|
private final boolean mHideSdkInfo;
|
||||||
|
|
||||||
|
public EventHandler(ResTable resTable) {
|
||||||
|
mResTable = resTable;
|
||||||
|
mHideSdkInfo = !resTable.getAnalysisMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onEvent(XmlPullParser in, XmlSerializer out) throws XmlPullParserException {
|
||||||
|
int type = in.getEventType();
|
||||||
|
|
||||||
|
if (type == XmlPullParser.START_TAG) {
|
||||||
|
String name = in.getName();
|
||||||
|
|
||||||
|
if (name.equals("manifest")) {
|
||||||
|
parseManifest(in);
|
||||||
|
} else if (name.equals("uses-sdk")) {
|
||||||
|
parseUsesSdk(in);
|
||||||
|
|
||||||
|
if (mHideSdkInfo) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == XmlPullParser.END_TAG) {
|
||||||
|
String name = in.getName();
|
||||||
|
|
||||||
|
if (name.equals("uses-sdk")) {
|
||||||
|
if (mHideSdkInfo) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseManifest(XmlPullParser in) {
|
||||||
|
for (int i = 0; i < in.getAttributeCount(); i++) {
|
||||||
|
String ns = in.getAttributeNamespace(i);
|
||||||
|
String name = in.getAttributeName(i);
|
||||||
|
String value = in.getAttributeValue(i);
|
||||||
|
|
||||||
|
if (value.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ns.isEmpty()) {
|
||||||
|
if (name.equals("package")) {
|
||||||
|
mResTable.setPackageRenamed(value);
|
||||||
|
}
|
||||||
|
} else if (ns.equals(AXmlResourceParser.ANDROID_RES_NS)) {
|
||||||
|
switch (name) {
|
||||||
|
case "versionCode":
|
||||||
|
mResTable.setVersionCode(value);
|
||||||
|
break;
|
||||||
|
case "versionName":
|
||||||
|
mResTable.setVersionName(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseUsesSdk(XmlPullParser in) {
|
||||||
|
for (int i = 0; i < in.getAttributeCount(); i++) {
|
||||||
|
String ns = in.getAttributeNamespace(i);
|
||||||
|
String name = in.getAttributeName(i);
|
||||||
|
String value = in.getAttributeValue(i);
|
||||||
|
|
||||||
|
if (value.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ns.equals(AXmlResourceParser.ANDROID_RES_NS)) {
|
||||||
|
switch (name) {
|
||||||
|
case "minSdkVersion":
|
||||||
|
case "targetSdkVersion":
|
||||||
|
case "maxSdkVersion":
|
||||||
|
case "compileSdkVersion":
|
||||||
|
mResTable.addSdkInfo(name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,45 +19,31 @@ package brut.androlib.res.decoder;
|
|||||||
import brut.androlib.exceptions.AndrolibException;
|
import brut.androlib.exceptions.AndrolibException;
|
||||||
import brut.androlib.exceptions.AXmlDecodingException;
|
import brut.androlib.exceptions.AXmlDecodingException;
|
||||||
import brut.androlib.exceptions.RawXmlEncounteredException;
|
import brut.androlib.exceptions.RawXmlEncounteredException;
|
||||||
import brut.androlib.res.util.ExtXmlSerializer;
|
import brut.xmlpull.XmlPullUtils;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
import org.xmlpull.v1.wrapper.XmlPullParserWrapper;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
import org.xmlpull.v1.wrapper.XmlPullWrapperFactory;
|
|
||||||
import org.xmlpull.v1.wrapper.XmlSerializerWrapper;
|
|
||||||
import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
public class ResXmlPullStreamDecoder implements ResStreamDecoder {
|
public class ResXmlPullStreamDecoder implements ResStreamDecoder {
|
||||||
public ResXmlPullStreamDecoder(AXmlResourceParser parser,
|
private final AXmlResourceParser mParser;
|
||||||
ExtXmlSerializer serializer) {
|
private final XmlSerializer mSerial;
|
||||||
this.mParser = parser;
|
|
||||||
this.mSerial = serializer;
|
public ResXmlPullStreamDecoder(AXmlResourceParser parser, XmlSerializer serial) {
|
||||||
|
mParser = parser;
|
||||||
|
mSerial = serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(InputStream in, OutputStream out)
|
public void decode(InputStream in, OutputStream out) throws AndrolibException {
|
||||||
throws AndrolibException {
|
|
||||||
try {
|
try {
|
||||||
XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
|
mParser.setInput(in, null);
|
||||||
XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
|
mSerial.setOutput(out, null);
|
||||||
XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial, factory);
|
XmlPullUtils.copy(mParser, mSerial);
|
||||||
|
|
||||||
par.setInput(in, null);
|
|
||||||
ser.setOutput(out, null);
|
|
||||||
|
|
||||||
while (par.nextToken() != XmlPullParser.END_DOCUMENT) {
|
|
||||||
ser.event(par);
|
|
||||||
}
|
|
||||||
ser.flush();
|
|
||||||
} catch (XmlPullParserException ex) {
|
} catch (XmlPullParserException ex) {
|
||||||
throw new AXmlDecodingException("Could not decode XML", ex);
|
throw new AXmlDecodingException("Could not decode XML", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new RawXmlEncounteredException("Could not decode XML", ex);
|
throw new RawXmlEncounteredException("Could not decode XML", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AXmlResourceParser mParser;
|
|
||||||
private final ExtXmlSerializer mSerial;
|
|
||||||
}
|
}
|
||||||
|
@ -1,76 +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.util;
|
|
||||||
|
|
||||||
import org.xmlpull.renamed.MXSerializer;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class ExtMXSerializer extends MXSerializer implements ExtXmlSerializer {
|
|
||||||
@Override
|
|
||||||
public void startDocument(String encoding, Boolean standalone)
|
|
||||||
throws IOException, IllegalArgumentException, IllegalStateException {
|
|
||||||
super.startDocument(encoding != null ? encoding : mDefaultEncoding, standalone);
|
|
||||||
this.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void writeAttributeValue(String value, Writer out) throws IOException {
|
|
||||||
if (mIsDisabledAttrEscape) {
|
|
||||||
out.write(value == null ? "" : value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.writeAttributeValue(value, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOutput(OutputStream os, String encoding) throws IOException {
|
|
||||||
super.setOutput(os, encoding != null ? encoding : mDefaultEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getProperty(String name) throws IllegalArgumentException {
|
|
||||||
if (PROPERTY_DEFAULT_ENCODING.equals(name)) {
|
|
||||||
return mDefaultEncoding;
|
|
||||||
}
|
|
||||||
return super.getProperty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setProperty(String name, Object value) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
if (PROPERTY_DEFAULT_ENCODING.equals(name)) {
|
|
||||||
mDefaultEncoding = (String) value;
|
|
||||||
} else {
|
|
||||||
super.setProperty(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ExtXmlSerializer newLine() throws IOException {
|
|
||||||
super.out.write(lineSeparator);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDisabledAttrEscape(boolean disabled) {
|
|
||||||
mIsDisabledAttrEscape = disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String mDefaultEncoding;
|
|
||||||
private boolean mIsDisabledAttrEscape = false;
|
|
||||||
|
|
||||||
}
|
|
@ -1,32 +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.util;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public interface ExtXmlSerializer extends XmlSerializer {
|
|
||||||
|
|
||||||
ExtXmlSerializer newLine() throws IOException;
|
|
||||||
|
|
||||||
void setDisabledAttrEscape(boolean disabled);
|
|
||||||
|
|
||||||
String PROPERTY_SERIALIZER_INDENTATION = "http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
|
|
||||||
String PROPERTY_SERIALIZER_LINE_SEPARATOR = "http://xmlpull.org/v1/doc/properties.html#serializer-line-separator";
|
|
||||||
String PROPERTY_DEFAULT_ENCODING = "DEFAULT_ENCODING";
|
|
||||||
}
|
|
@ -23,12 +23,15 @@ import org.xml.sax.SAXException;
|
|||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.OutputKeys;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import javax.xml.xpath.*;
|
import javax.xml.xpath.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -436,11 +439,19 @@ public final class ResXmlPatcher {
|
|||||||
private static void saveDocument(File file, Document doc)
|
private static void saveDocument(File file, Document doc)
|
||||||
throws IOException, SAXException, ParserConfigurationException, TransformerException {
|
throws IOException, SAXException, ParserConfigurationException, TransformerException {
|
||||||
|
|
||||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
TransformerFactory factory = TransformerFactory.newInstance();
|
||||||
Transformer transformer = transformerFactory.newTransformer();
|
Transformer transformer = factory.newTransformer();
|
||||||
DOMSource source = new DOMSource(doc);
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
|
||||||
StreamResult result = new StreamResult(file);
|
|
||||||
transformer.transform(source, result);
|
byte[] xmlDecl = "<?xml version=\"1.0\" encoding=\"utf-8\"?>".getBytes(StandardCharsets.US_ASCII);
|
||||||
|
byte[] newLine = System.getProperty("line.separator").getBytes(StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
try (OutputStream output = Files.newOutputStream(file.toPath())) {
|
||||||
|
output.write(xmlDecl);
|
||||||
|
output.write(newLine);
|
||||||
|
transformer.transform(new DOMSource(doc), new StreamResult(output));
|
||||||
|
output.write(newLine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
|
private static final String ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
|
||||||
|
@ -25,12 +25,16 @@ import brut.directory.Directory;
|
|||||||
import brut.directory.FileDirectory;
|
import brut.directory.FileDirectory;
|
||||||
import brut.util.OS;
|
import brut.util.OS;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
import org.xmlpull.v1.XmlPullParserFactory;
|
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
@ -40,43 +44,24 @@ import java.util.Map;
|
|||||||
|
|
||||||
public abstract class TestUtils {
|
public abstract class TestUtils {
|
||||||
|
|
||||||
public static Map<String, String> parseStringsXml(File file)
|
public static Map<String, String> parseStringsXml(File file) throws BrutException {
|
||||||
throws BrutException {
|
|
||||||
try {
|
try {
|
||||||
XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
|
Document doc = getDocumentFromFile(file);
|
||||||
xpp.setInput(new FileReader(file));
|
XPath xPath = XPathFactory.newInstance().newXPath();
|
||||||
|
String expression = "/resources/string[@name]";
|
||||||
|
NodeList nodes = (NodeList) xPath.evaluate(expression, doc, XPathConstants.NODESET);
|
||||||
|
|
||||||
int eventType;
|
|
||||||
String key = null;
|
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
while ((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) {
|
|
||||||
switch (eventType) {
|
for (int i = 0; i < nodes.getLength(); i++) {
|
||||||
case XmlPullParser.START_TAG:
|
Node node = nodes.item(i);
|
||||||
if ("string".equals(xpp.getName())) {
|
NamedNodeMap attrs = node.getAttributes();
|
||||||
int attrCount = xpp.getAttributeCount();
|
Node nameAttr = attrs.getNamedItem("name");
|
||||||
for (int i = 0; i < attrCount; i++) {
|
map.put(nameAttr.getNodeValue(), node.getTextContent());
|
||||||
if ("name".equals(xpp.getAttributeName(i))) {
|
|
||||||
key = xpp.getAttributeValue(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XmlPullParser.END_TAG:
|
|
||||||
if ("string".equals(xpp.getName())) {
|
|
||||||
key = null;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XmlPullParser.TEXT:
|
|
||||||
if (key != null) {
|
|
||||||
map.put(key, xpp.getText());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
} catch (IOException | XmlPullParserException ex) {
|
} catch (XPathExpressionException ex) {
|
||||||
throw new BrutException(ex);
|
throw new BrutException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +69,7 @@ public abstract class TestUtils {
|
|||||||
public static Document getDocumentFromFile(File file) throws BrutException {
|
public static Document getDocumentFromFile(File file) throws BrutException {
|
||||||
try {
|
try {
|
||||||
return ResXmlPatcher.loadDocument(file);
|
return ResXmlPatcher.loadDocument(file);
|
||||||
} catch (ParserConfigurationException | SAXException | IOException ex) {
|
} catch (IOException | SAXException | ParserConfigurationException ex) {
|
||||||
throw new BrutException(ex);
|
throw new BrutException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,5 @@
|
|||||||
<meta-data name="test_int" value="12345" />
|
<meta-data name="test_int" value="12345" />
|
||||||
</application>
|
</application>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
|
||||||
<permission android:featureFlag="brut.feature.flag" android:label="Test Permission" android:name="brut.permission.TEST" android:permissionGroup="android.permission-group.UNDEFINED" android:protectionLevel="signature"/>
|
<permission android:featureFlag="brut.feature.flag" android:label="Test Permission" android:name="brut.permission.TEST" android:permissionGroup="android.permission-group.UNDEFINED" android:protectionLevel="signature" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":brut.j.common"))
|
implementation(project(":brut.j.common"))
|
||||||
implementation(project(":brut.j.util"))
|
implementation(project(":brut.j.util"))
|
||||||
implementation(libs.commons.io)
|
implementation(libs.commons.io)
|
||||||
}
|
}
|
||||||
|
3
brut.j.xml/build.gradle.kts
Normal file
3
brut.j.xml/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dependencies {
|
||||||
|
api(libs.xmlpull)
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
122
brut.j.xml/src/main/java/brut/xmlpull/XmlPullUtils.java
Normal file
122
brut.j.xml/src/main/java/brut/xmlpull/XmlPullUtils.java
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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.xmlpull;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class XmlPullUtils {
|
||||||
|
private static final String PROPERTY_XMLDECL_STANDALONE
|
||||||
|
= "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone";
|
||||||
|
|
||||||
|
public interface EventHandler {
|
||||||
|
boolean onEvent(XmlPullParser in, XmlSerializer out) throws XmlPullParserException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copy(XmlPullParser in, XmlSerializer out)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
copy(in, out, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copy(XmlPullParser in, XmlSerializer out, EventHandler handler)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
Boolean standalone = (Boolean) in.getProperty(PROPERTY_XMLDECL_STANDALONE);
|
||||||
|
|
||||||
|
// Some parsers may have already consumed the event that starts the
|
||||||
|
// document, so we manually emit that event here for consistency
|
||||||
|
if (in.getEventType() == XmlPullParser.START_DOCUMENT) {
|
||||||
|
out.startDocument(in.getInputEncoding(), standalone);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int event = in.nextToken();
|
||||||
|
if (event == XmlPullParser.START_DOCUMENT) {
|
||||||
|
out.startDocument(in.getInputEncoding(), standalone);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (event == XmlPullParser.END_DOCUMENT) {
|
||||||
|
out.endDocument();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (handler != null && handler.onEvent(in, out)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (event) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
if (!in.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES)) {
|
||||||
|
int nsStart = in.getNamespaceCount(in.getDepth() - 1);
|
||||||
|
int nsEnd = in.getNamespaceCount(in.getDepth());
|
||||||
|
for (int i = nsStart; i < nsEnd; i++) {
|
||||||
|
String prefix = in.getNamespacePrefix(i);
|
||||||
|
String ns = in.getNamespaceUri(i);
|
||||||
|
out.setPrefix(prefix, ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.startTag(normalizeNamespace(in.getNamespace()), in.getName());
|
||||||
|
for (int i = 0; i < in.getAttributeCount(); i++) {
|
||||||
|
String ns = normalizeNamespace(in.getAttributeNamespace(i));
|
||||||
|
String name = in.getAttributeName(i);
|
||||||
|
String value = in.getAttributeValue(i);
|
||||||
|
out.attribute(ns, name, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
out.endTag(normalizeNamespace(in.getNamespace()), in.getName());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.TEXT:
|
||||||
|
out.text(in.getText());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.CDSECT:
|
||||||
|
out.cdsect(in.getText());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.ENTITY_REF:
|
||||||
|
out.entityRef(in.getName());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.IGNORABLE_WHITESPACE:
|
||||||
|
out.ignorableWhitespace(in.getText());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.PROCESSING_INSTRUCTION:
|
||||||
|
out.processingInstruction(in.getText());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.COMMENT:
|
||||||
|
out.comment(in.getText());
|
||||||
|
break;
|
||||||
|
case XmlPullParser.DOCDECL:
|
||||||
|
out.docdecl(in.getText());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown event: " + event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some parsers may return an empty string when a namespace in unsupported,
|
||||||
|
* which can confuse serializers. This method normalizes empty strings to
|
||||||
|
* be null.
|
||||||
|
*/
|
||||||
|
private static String normalizeNamespace(String namespace) {
|
||||||
|
if (namespace == null || namespace.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -83,7 +83,7 @@ subprojects {
|
|||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
val mavenProjects = arrayOf("apktool-lib", "apktool-cli", "brut.j.common", "brut.j.util", "brut.j.dir")
|
val mavenProjects = arrayOf("brut.j.common", "brut.j.util", "brut.j.dir", "brut.j.xml", "apktool-lib", "apktool-cli")
|
||||||
|
|
||||||
if (project.name in mavenProjects) {
|
if (project.name in mavenProjects) {
|
||||||
apply(plugin = "maven-publish")
|
apply(plugin = "maven-publish")
|
||||||
|
@ -8,7 +8,7 @@ guava = "33.3.1-jre"
|
|||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
r8 = "8.5.35"
|
r8 = "8.5.35"
|
||||||
smali = "3.0.8"
|
smali = "3.0.8"
|
||||||
xmlpull = "1.1.6"
|
xmlpull = "1.1.3.1"
|
||||||
xmlunit = "2.10.0"
|
xmlunit = "2.10.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@ -21,5 +21,5 @@ guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
|||||||
junit = { module = "junit:junit", version.ref = "junit" }
|
junit = { module = "junit:junit", version.ref = "junit" }
|
||||||
r8 = { module = "com.android.tools:r8", version.ref = "r8" }
|
r8 = { module = "com.android.tools:r8", version.ref = "r8" }
|
||||||
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
||||||
xmlpull = { module = "org.ogce:xpp3", version.ref = "xmlpull" }
|
xmlpull = { module = "xmlpull:xmlpull", version.ref = "xmlpull" }
|
||||||
xmlunit = { module = "org.xmlunit:xmlunit-legacy", version.ref = "xmlunit" }
|
xmlunit = { module = "org.xmlunit:xmlunit-legacy", version.ref = "xmlunit" }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
rootProject.name = "apktool-cli"
|
rootProject.name = "apktool-cli"
|
||||||
include("brut.j.common", "brut.j.util", "brut.j.dir", "brut.apktool:apktool-lib", "brut.apktool:apktool-cli")
|
include("brut.j.common", "brut.j.util", "brut.j.dir", "brut.j.xml", "brut.apktool:apktool-lib", "brut.apktool:apktool-cli")
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
versionCatalogs {
|
versionCatalogs {
|
||||||
|
Loading…
Reference in New Issue
Block a user