mirror of
https://github.com/revanced/Apktool.git
synced 2025-06-12 13:17:43 +02:00
Merge branch 'master' into patch-1
This commit is contained in:
@ -416,7 +416,7 @@ public class Androlib {
|
||||
if (apkOptions.forceBuildAll || isModified(smaliDir, dex)) {
|
||||
LOGGER.info("Smaling " + folder + " folder into " + filename + "...");
|
||||
dex.delete();
|
||||
SmaliBuilder.build(smaliDir, dex, mMinSdkVersion);
|
||||
SmaliBuilder.build(smaliDir, dex, apkOptions.forceApi > 0 ? apkOptions.forceApi : mMinSdkVersion);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -377,6 +377,25 @@ public class ApkDecoder {
|
||||
private void putSdkInfo(MetaInfo meta) throws AndrolibException {
|
||||
Map<String, String> info = getResTable().getSdkInfo();
|
||||
if (info.size() > 0) {
|
||||
String refValue;
|
||||
if (info.get("minSdkVersion") != null) {
|
||||
refValue = ResXmlPatcher.pullValueFromIntegers(mOutDir, info.get("minSdkVersion"));
|
||||
if (refValue != null) {
|
||||
info.put("minSdkVersion", refValue);
|
||||
}
|
||||
}
|
||||
if (info.get("targetSdkVersion") != null) {
|
||||
refValue = ResXmlPatcher.pullValueFromIntegers(mOutDir, info.get("targetSdkVersion"));
|
||||
if (refValue != null) {
|
||||
info.put("targetSdkVersion", refValue);
|
||||
}
|
||||
}
|
||||
if (info.get("maxSdkVersion") != null) {
|
||||
refValue = ResXmlPatcher.pullValueFromIntegers(mOutDir, info.get("maxSdkVersion"));
|
||||
if (refValue != null) {
|
||||
info.put("maxSdkVersion", refValue);
|
||||
}
|
||||
}
|
||||
meta.sdkInfo = info;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ public class ApkOptions {
|
||||
public boolean isFramework = false;
|
||||
public boolean resourcesAreCompressed = false;
|
||||
public boolean useAapt2 = false;
|
||||
public boolean noCrunch = false;
|
||||
public int forceApi = 0;
|
||||
public Collection<String> doNotCompress;
|
||||
|
||||
public String frameworkFolderLocation = null;
|
||||
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (C) 2018 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
* Copyright (C) 2018 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
|
||||
*
|
||||
* http://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.err;
|
||||
|
||||
import brut.androlib.AndrolibException;
|
||||
|
||||
public class AXmlDecodingException extends AndrolibException {
|
||||
|
||||
public AXmlDecodingException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public AXmlDecodingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public AXmlDecodingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AXmlDecodingException() {
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (C) 2018 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
* Copyright (C) 2018 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
|
||||
*
|
||||
* http://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.err;
|
||||
|
||||
import brut.androlib.AndrolibException;
|
||||
|
||||
public class RawXmlEncounteredException extends AndrolibException {
|
||||
|
||||
public RawXmlEncounteredException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public RawXmlEncounteredException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RawXmlEncounteredException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RawXmlEncounteredException() {
|
||||
}
|
||||
}
|
@ -29,14 +29,14 @@ import org.jf.smali.*;
|
||||
*/
|
||||
public class SmaliMod {
|
||||
|
||||
public static boolean assembleSmaliFile(String smali, DexBuilder dexBuilder, boolean verboseErrors,
|
||||
public static boolean assembleSmaliFile(String smali, DexBuilder dexBuilder, int apiLevel, boolean verboseErrors,
|
||||
boolean printTokens, File smaliFile) throws IOException, RuntimeException, RecognitionException {
|
||||
|
||||
InputStream is = new ByteArrayInputStream(smali.getBytes());
|
||||
return assembleSmaliFile(is, dexBuilder, verboseErrors, printTokens, smaliFile);
|
||||
return assembleSmaliFile(is, dexBuilder, apiLevel, verboseErrors, printTokens, smaliFile);
|
||||
}
|
||||
|
||||
public static boolean assembleSmaliFile(InputStream is,DexBuilder dexBuilder, boolean verboseErrors,
|
||||
public static boolean assembleSmaliFile(InputStream is,DexBuilder dexBuilder, int apiLevel, boolean verboseErrors,
|
||||
boolean printTokens, File smaliFile) throws IOException, RecognitionException {
|
||||
|
||||
// copy our filestream into a tmp file, so we don't overwrite
|
||||
@ -47,10 +47,10 @@ public class SmaliMod {
|
||||
IOUtils.copy(is, os);
|
||||
os.close();
|
||||
|
||||
return assembleSmaliFile(tmp,dexBuilder, verboseErrors, printTokens);
|
||||
return assembleSmaliFile(tmp,dexBuilder, apiLevel, verboseErrors, printTokens);
|
||||
}
|
||||
|
||||
public static boolean assembleSmaliFile(File smaliFile,DexBuilder dexBuilder, boolean verboseErrors,
|
||||
public static boolean assembleSmaliFile(File smaliFile,DexBuilder dexBuilder, int apiLevel, boolean verboseErrors,
|
||||
boolean printTokens) throws IOException, RecognitionException {
|
||||
|
||||
CommonTokenStream tokens;
|
||||
@ -77,6 +77,7 @@ public class SmaliMod {
|
||||
}
|
||||
|
||||
smaliParser parser = new smaliParser(tokens);
|
||||
parser.setApiLevel(apiLevel);
|
||||
parser.setVerboseErrors(verboseErrors);
|
||||
|
||||
smaliParser.smali_file_return result = parser.smali_file();
|
||||
@ -93,7 +94,7 @@ public class SmaliMod {
|
||||
treeStream.setTokenStream(tokens);
|
||||
|
||||
smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
|
||||
|
||||
dexGen.setApiLevel(apiLevel);
|
||||
dexGen.setVerboseErrors(verboseErrors);
|
||||
dexGen.setDexBuilder(dexBuilder);
|
||||
dexGen.smali_file();
|
||||
|
@ -350,6 +350,10 @@ final public class AndrolibResources {
|
||||
cmd.add("-v");
|
||||
}
|
||||
|
||||
if (apkOptions.noCrunch) {
|
||||
cmd.add("--no-crunch");
|
||||
}
|
||||
|
||||
try {
|
||||
OS.exec(cmd.toArray(new String[0]));
|
||||
LOGGER.fine("aapt2 compile command ran: ");
|
||||
@ -485,6 +489,9 @@ final public class AndrolibResources {
|
||||
if (apkOptions.debugMode) { // inject debuggable="true" into manifest
|
||||
cmd.add("--debug-mode");
|
||||
}
|
||||
if (apkOptions.noCrunch) {
|
||||
cmd.add("--no-crunch");
|
||||
}
|
||||
// force package id so that some frameworks build with correct id
|
||||
// disable if user adds own aapt (can't know if they have this feature)
|
||||
if (mPackageId != null && ! customAapt && ! mSharedLibrary) {
|
||||
|
@ -24,6 +24,11 @@ import java.util.*;
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
*/
|
||||
public final class ResTypeSpec {
|
||||
|
||||
public static final String RES_TYPE_NAME_ARRAY = "array";
|
||||
public static final String RES_TYPE_NAME_PLURALS = "plurals";
|
||||
public static final String RES_TYPE_NAME_STYLES = "style";
|
||||
|
||||
private final String mName;
|
||||
private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();
|
||||
|
||||
|
@ -83,6 +83,13 @@ public abstract class ResScalarValue extends ResIntBasedValue implements
|
||||
}
|
||||
}
|
||||
|
||||
// Android does not allow values (false) for ids.xml anymore
|
||||
// https://issuetracker.google.com/issues/80475496
|
||||
// But it decodes as a ResBoolean, which makes no sense. So force it to empty
|
||||
if (type.equalsIgnoreCase("id") && !body.isEmpty()) {
|
||||
body = "";
|
||||
}
|
||||
|
||||
// check for using attrib as node or item
|
||||
String tagName = item ? "item" : type;
|
||||
|
||||
|
@ -19,6 +19,7 @@ package brut.androlib.res.data.value;
|
||||
import android.util.TypedValue;
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.res.data.ResPackage;
|
||||
import brut.androlib.res.data.ResTypeSpec;
|
||||
import brut.util.Duo;
|
||||
|
||||
/**
|
||||
@ -41,7 +42,7 @@ public class ResValueFactory {
|
||||
}
|
||||
return new ResReferenceValue(mPackage, 0, null);
|
||||
case TypedValue.TYPE_REFERENCE:
|
||||
return newReference(value, rawValue);
|
||||
return newReference(value, null);
|
||||
case TypedValue.TYPE_ATTRIBUTE:
|
||||
return newReference(value, rawValue, true);
|
||||
case TypedValue.TYPE_STRING:
|
||||
@ -83,7 +84,7 @@ public class ResValueFactory {
|
||||
return new ResStringValue(value, rawValue);
|
||||
}
|
||||
|
||||
public ResBagValue bagFactory(int parent, Duo<Integer, ResScalarValue>[] items) throws AndrolibException {
|
||||
public ResBagValue bagFactory(int parent, Duo<Integer, ResScalarValue>[] items, ResTypeSpec resTypeSpec) throws AndrolibException {
|
||||
ResReferenceValue parentVal = newReference(parent, null);
|
||||
|
||||
if (items.length == 0) {
|
||||
@ -93,14 +94,25 @@ public class ResValueFactory {
|
||||
if (key == ResAttr.BAG_KEY_ATTR_TYPE) {
|
||||
return ResAttr.factory(parentVal, items, this, mPackage);
|
||||
}
|
||||
// Android O Preview added an unknown enum for ResTable_map. This is hardcoded as 0 for now.
|
||||
if (key == ResArrayValue.BAG_KEY_ARRAY_START || key == 0) {
|
||||
|
||||
String resTypeName = resTypeSpec.getName();
|
||||
|
||||
// Android O Preview added an unknown enum for c. This is hardcoded as 0 for now.
|
||||
if (ResTypeSpec.RES_TYPE_NAME_ARRAY.equals(resTypeName)
|
||||
|| key == ResArrayValue.BAG_KEY_ARRAY_START || key == 0) {
|
||||
return new ResArrayValue(parentVal, items);
|
||||
}
|
||||
if (key >= ResPluralsValue.BAG_KEY_PLURALS_START && key <= ResPluralsValue.BAG_KEY_PLURALS_END) {
|
||||
|
||||
if (ResTypeSpec.RES_TYPE_NAME_PLURALS.equals(resTypeName) ||
|
||||
(key >= ResPluralsValue.BAG_KEY_PLURALS_START && key <= ResPluralsValue.BAG_KEY_PLURALS_END)) {
|
||||
return new ResPluralsValue(parentVal, items);
|
||||
}
|
||||
return new ResStyleValue(parentVal, items, this);
|
||||
|
||||
if (ResTypeSpec.RES_TYPE_NAME_STYLES.equals(resTypeName)) {
|
||||
return new ResStyleValue(parentVal, items, this);
|
||||
}
|
||||
|
||||
throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
|
||||
}
|
||||
|
||||
public ResReferenceValue newReference(int resID, String rawValue) {
|
||||
|
@ -347,7 +347,7 @@ public class ARSCDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
return factory.bagFactory(parent, items);
|
||||
return factory.bagFactory(parent, items, mTypeSpec);
|
||||
}
|
||||
|
||||
private ResIntBasedValue readValue() throws IOException, AndrolibException {
|
||||
|
@ -852,7 +852,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
private final void doNext() throws IOException {
|
||||
// Delayed initialization.
|
||||
if (m_strings == null) {
|
||||
m_reader.skipCheckInt(CHUNK_AXML_FILE);
|
||||
m_reader.skipCheckInt(CHUNK_AXML_FILE, CHUNK_AXML_FILE_BROKEN);
|
||||
|
||||
/*
|
||||
* chunkSize
|
||||
@ -1004,7 +1004,7 @@ public class AXmlResourceParser implements XmlResourceParser {
|
||||
ATTRIBUTE_IX_VALUE_TYPE = 3, ATTRIBUTE_IX_VALUE_DATA = 4,
|
||||
ATTRIBUTE_LENGTH = 5;
|
||||
|
||||
private static final int CHUNK_AXML_FILE = 0x00080003,
|
||||
private static final int CHUNK_AXML_FILE = 0x00080003, CHUNK_AXML_FILE_BROKEN = 0x00080001,
|
||||
CHUNK_RESOURCEIDS = 0x00080180, CHUNK_XML_FIRST = 0x00100100,
|
||||
CHUNK_XML_START_NAMESPACE = 0x00100100,
|
||||
CHUNK_XML_END_NAMESPACE = 0x00100101,
|
||||
|
@ -65,13 +65,21 @@ public class Res9patchStreamDecoder implements ResStreamDecoder {
|
||||
drawVLine(im2, w + 1, np.padTop + 1, h - np.padBottom);
|
||||
|
||||
int[] xDivs = np.xDivs;
|
||||
for (int i = 0; i < xDivs.length; i += 2) {
|
||||
drawHLine(im2, 0, xDivs[i] + 1, xDivs[i + 1]);
|
||||
if (xDivs.length == 0) {
|
||||
drawHLine(im2, 0, 1, w);
|
||||
} else {
|
||||
for (int i = 0; i < xDivs.length; i += 2) {
|
||||
drawHLine(im2, 0, xDivs[i] + 1, xDivs[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
int[] yDivs = np.yDivs;
|
||||
for (int i = 0; i < yDivs.length; i += 2) {
|
||||
drawVLine(im2, 0, yDivs[i] + 1, yDivs[i + 1]);
|
||||
if (yDivs.length == 0) {
|
||||
drawVLine(im2, 0, 1, h);
|
||||
} else {
|
||||
for (int i = 0; i < yDivs.length; i += 2) {
|
||||
drawVLine(im2, 0, yDivs[i] + 1, yDivs[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Some images additionally use Optical Bounds
|
||||
|
@ -18,6 +18,7 @@ package brut.androlib.res.decoder;
|
||||
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.err.CantFind9PatchChunk;
|
||||
import brut.androlib.err.RawXmlEncounteredException;
|
||||
import brut.androlib.res.data.ResResource;
|
||||
import brut.androlib.res.data.value.ResBoolValue;
|
||||
import brut.androlib.res.data.value.ResFileValue;
|
||||
@ -118,6 +119,11 @@ public class ResFileDecoder {
|
||||
}
|
||||
|
||||
decode(inDir, inFileName, outDir, outFileName, "xml");
|
||||
} catch (RawXmlEncounteredException ex) {
|
||||
// If we got an error to decode XML, lets assume the file is in raw format.
|
||||
// This is a large assumption, that might increase runtime, but will save us for situations where
|
||||
// XSD files are AXML`d on aapt1, but left in plaintext in aapt2.
|
||||
decode(inDir, inFileName, outDir, outFileName, "raw");
|
||||
} catch (AndrolibException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format(
|
||||
"Could not decode file, replacing by FALSE value: %s",
|
||||
|
@ -19,8 +19,9 @@ package brut.androlib.res.decoder;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import brut.androlib.err.AXmlDecodingException;
|
||||
import brut.androlib.err.RawXmlEncounteredException;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.wrapper.XmlPullParserWrapper;
|
||||
@ -142,9 +143,9 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
|
||||
}
|
||||
ser.flush();
|
||||
} catch (XmlPullParserException ex) {
|
||||
throw new AndrolibException("Could not decode XML", ex);
|
||||
throw new AXmlDecodingException("Could not decode XML", ex);
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException("Could not decode XML", ex);
|
||||
throw new RawXmlEncounteredException("Could not decode XML", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,6 +156,4 @@ public class XmlPullStreamDecoder implements ResStreamDecoder {
|
||||
|
||||
private final XmlPullParser mParser;
|
||||
private final ExtXmlSerializer mSerial;
|
||||
|
||||
private final static Logger LOGGER = Logger.getLogger(XmlPullStreamDecoder.class.getName());
|
||||
}
|
||||
|
@ -197,6 +197,41 @@ public final class ResXmlPatcher {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds key in integers.xml file and returns text value
|
||||
*
|
||||
* @param directory Root directory of apk
|
||||
* @param key Integer reference (ie @integer/foo)
|
||||
* @return String|null
|
||||
* @throws AndrolibException
|
||||
*/
|
||||
public static String pullValueFromIntegers(File directory, String key) throws AndrolibException {
|
||||
if (key == null || ! key.contains("@")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(directory, "/res/values/integers.xml");
|
||||
key = key.replace("@integer/", "");
|
||||
|
||||
if (file.exists()) {
|
||||
try {
|
||||
Document doc = loadDocument(file);
|
||||
XPath xPath = XPathFactory.newInstance().newXPath();
|
||||
XPathExpression expression = xPath.compile("/resources/integer[@name=" + '"' + key + "\"]/text()");
|
||||
|
||||
Object result = expression.evaluate(doc, XPathConstants.STRING);
|
||||
|
||||
if (result != null) {
|
||||
return (String) result;
|
||||
}
|
||||
|
||||
} catch (SAXException | ParserConfigurationException | IOException | XPathExpressionException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes attributes like "versionCode" and "versionName" from file.
|
||||
*
|
||||
|
@ -71,7 +71,7 @@ public class SmaliBuilder {
|
||||
|
||||
if (fileName.endsWith(".smali")) {
|
||||
try {
|
||||
if (!SmaliMod.assembleSmaliFile(inFile, dexBuilder, false, false)) {
|
||||
if (!SmaliMod.assembleSmaliFile(inFile, dexBuilder, mApiLevel, false, false)) {
|
||||
throw new AndrolibException("Could not smali file: " + fileName);
|
||||
}
|
||||
} catch (IOException | RecognitionException ex) {
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2_64
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2_64
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt_64
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt_64
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt2_64
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt2_64
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt_64
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt_64
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt.exe
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt.exe
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2.exe
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2.exe
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2_64.exe
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2_64.exe
Executable file
Binary file not shown.
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt_64.exe
Executable file
BIN
brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt_64.exe
Executable file
Binary file not shown.
@ -198,6 +198,16 @@ public class BuildAndDecodeTest extends BaseTest {
|
||||
compareXmlFiles("res/xml/references.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlXsdFileTest() throws BrutException {
|
||||
compareXmlFiles("res/xml/ww_box_styles_schema.xsd");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlIdsEmptyTest() throws BrutException {
|
||||
compareXmlFiles("res/values/ids.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlReferenceAttributeTest() throws BrutException {
|
||||
compareXmlFiles("res/layout/issue1040.xml");
|
||||
@ -231,7 +241,7 @@ public class BuildAndDecodeTest extends BaseTest {
|
||||
@Test
|
||||
public void qualifiersTest() throws BrutException {
|
||||
compareValuesFiles("values-mcc004-mnc4-en-rUS-ldrtl-sw100dp-w200dp-h300dp"
|
||||
+ "-xlarge-long-round-highdr-land-desk-night-xhdpi-finger-keyssoft-12key"
|
||||
+ "-long-round-highdr-land-desk-night-xhdpi-finger-keyssoft-12key"
|
||||
+ "-navhidden-dpad-v26/strings.xml");
|
||||
}
|
||||
|
||||
|
@ -77,8 +77,8 @@ public class DebugTagRetainedTest extends BaseTest {
|
||||
|
||||
String expected = TestUtils.replaceNewlines("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>" +
|
||||
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" android:compileSdkVersion=\"23\" " +
|
||||
"android:compileSdkVersionCodename=\"6.0-2438415\" package=\"com.ibotpeaches.issue1235\" platformBuildVersionCode=\"23\" " +
|
||||
"platformBuildVersionName=\"6.0-2438415\"> <application android:debuggable=\"true\"/></manifest>");
|
||||
"android:compileSdkVersionCodename=\"6.0-2438415\" package=\"com.ibotpeaches.issue1235\" platformBuildVersionCode=\"20\" " +
|
||||
"platformBuildVersionName=\"4.4W.2-1537038\"> <application android:debuggable=\"true\"/></manifest>");
|
||||
|
||||
byte[] encoded = Files.readAllBytes(Paths.get(sTmpDir + File.separator + apk + File.separator + "AndroidManifest.xml"));
|
||||
String obtained = TestUtils.replaceNewlines(new String(encoded));
|
||||
|
@ -72,7 +72,7 @@ public class ProviderAttributeTest extends BaseTest {
|
||||
apkDecoder.decode();
|
||||
|
||||
String expected = TestUtils.replaceNewlines("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n" +
|
||||
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" android:compileSdkVersion=\"23\" android:compileSdkVersionCodename=\"6.0-2438415\" package=\"com.ibotpeaches.issue636\" platformBuildVersionCode=\"23\" platformBuildVersionName=\"6.0-2438415\">\n" +
|
||||
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" android:compileSdkVersion=\"23\" android:compileSdkVersionCodename=\"6.0-2438415\" package=\"com.ibotpeaches.issue636\" platformBuildVersionCode=\"22\" platformBuildVersionName=\"5.1-1756733\">\n" +
|
||||
" <application android:allowBackup=\"true\" android:debuggable=\"true\" android:icon=\"@mipmap/ic_launcher\" android:label=\"@string/app_name\" android:theme=\"@style/AppTheme\">\n" +
|
||||
" <provider android:authorities=\"com.ibotpeaches.issue636.Provider\" android:exported=\"false\" android:grantUriPermissions=\"true\" android:label=\"@string/app_name\" android:multiprocess=\"false\" android:name=\"com.ibotpeaches.issue636.Provider\"/>\n" +
|
||||
" <provider android:authorities=\"com.ibotpeaches.issue636.ProviderTwo\" android:exported=\"false\" android:grantUriPermissions=\"true\" android:label=\"@string/app_name\" android:multiprocess=\"false\" android:name=\"com.ibotpeaches.issue636.ProviderTwo\"/>\n" +
|
||||
|
@ -84,6 +84,11 @@ public class BuildAndDecodeTest extends BaseTest {
|
||||
compareXmlFiles("res/navigation/nav_graph.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlIdsEmptyTest() throws BrutException {
|
||||
compareXmlFiles("res/values/ids.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void leadingDollarSignResourceNameTest() throws BrutException {
|
||||
compareXmlFiles("res/drawable/$avd_hide_password__0.xml");
|
||||
@ -93,4 +98,9 @@ public class BuildAndDecodeTest extends BaseTest {
|
||||
public void confirmManifestStructureTest() throws BrutException {
|
||||
compareXmlFiles("AndroidManifest.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void xmlXsdFileTest() throws BrutException {
|
||||
compareXmlFiles("res/xml/ww_box_styles_schema.xsd");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
package brut.androlib.decode;
|
||||
|
||||
import brut.androlib.ApkDecoder;
|
||||
import brut.androlib.BaseTest;
|
||||
import brut.androlib.TestUtils;
|
||||
import brut.androlib.res.data.ResTable;
|
||||
import brut.androlib.res.data.value.ResArrayValue;
|
||||
import brut.androlib.res.data.value.ResValue;
|
||||
import brut.common.BrutException;
|
||||
import brut.directory.ExtFile;
|
||||
import brut.util.OS;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
public class DecodeArrayTest extends BaseTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
TestUtils.cleanFrameworkFile();
|
||||
sTmpDir = new ExtFile(OS.createTempDirectory());
|
||||
TestUtils.copyResourceDir(MissingVersionManifestTest.class, "decode/issue1994/", sTmpDir);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws BrutException {
|
||||
OS.rmdir(sTmpDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeStringArray() throws BrutException {
|
||||
String apk = "issue1994.apk";
|
||||
ApkDecoder apkDecoder = new ApkDecoder(new File(sTmpDir + File.separator + apk));
|
||||
|
||||
ResTable resTable = apkDecoder.getResTable();
|
||||
ResValue value = resTable.getResSpec(0x7f020001).getDefaultResource().getValue();
|
||||
|
||||
assertTrue("Not a ResArrayValue. Found: " + value.getClass(), value instanceof ResArrayValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodeArray() throws BrutException {
|
||||
String apk = "issue1994.apk";
|
||||
ApkDecoder apkDecoder = new ApkDecoder(new File(sTmpDir + File.separator + apk));
|
||||
|
||||
ResTable resTable = apkDecoder.getResTable();
|
||||
ResValue value = resTable.getResSpec(0x7f020000).getDefaultResource().getValue();
|
||||
|
||||
assertTrue("Not a ResArrayValue. Found: " + value.getClass(), value instanceof ResArrayValue);
|
||||
}
|
||||
}
|
@ -64,7 +64,7 @@ public class ExternalEntityTest extends BaseTest {
|
||||
|
||||
String expected = TestUtils.replaceNewlines("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<manifest android:versionCode=\"1\" android:versionName=\"1.0\" android:compileSdkVersion=\"23\" android:compileSdkVersionCodename=\"6.0-2438415\" " +
|
||||
"hardwareAccelerated=\"true\" package=\"com.ibotpeaches.doctype\" platformBuildVersionCode=\"23\" platformBuildVersionName=\"6.0-2438415\" " +
|
||||
"hardwareAccelerated=\"true\" package=\"com.ibotpeaches.doctype\" platformBuildVersionCode=\"24\" platformBuildVersionName=\"6.0-2456767\" " +
|
||||
"xmlns:android=\"http://schemas.android.com/apk/res/android\"> <supports-screens android:anyDensity=\"true\" android:smallScreens=\"true\" " +
|
||||
"android:normalScreens=\"true\" android:largeScreens=\"true\" android:resizeable=\"true\" android:xlargeScreens=\"true\" /></manifest>");
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (C) 2018 Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
* Copyright (C) 2018 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
|
||||
*
|
||||
* http://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.decode;
|
||||
|
||||
import brut.androlib.BaseTest;
|
||||
import brut.androlib.TestUtils;
|
||||
import brut.androlib.res.decoder.Res9patchStreamDecoder;
|
||||
import brut.common.BrutException;
|
||||
import brut.directory.ExtFile;
|
||||
import brut.util.OS;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class MissingDiv9PatchTest extends BaseTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
TestUtils.cleanFrameworkFile();
|
||||
sTmpDir = new ExtFile(OS.createTempDirectory());
|
||||
TestUtils.copyResourceDir(MissingDiv9PatchTest.class, "decode/issue1522/", sTmpDir);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws BrutException {
|
||||
OS.rmdir(sTmpDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertMissingDivAdded() throws Exception {
|
||||
InputStream inputStream = getFileInputStream();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
Res9patchStreamDecoder decoder = new Res9patchStreamDecoder();
|
||||
decoder.decode(inputStream, outputStream);
|
||||
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(outputStream.toByteArray()));
|
||||
int height = image.getHeight() - 1;
|
||||
|
||||
// First and last pixel will be invisible, so lets check the first column and ensure its all black
|
||||
for (int y = 1; y < height; y++) {
|
||||
assertEquals("y coordinate failed at: " + y, NP_COLOR, image.getRGB(0, y));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private FileInputStream getFileInputStream() throws IOException {
|
||||
File file = new File(sTmpDir, "pip_dismiss_scrim.9.png");
|
||||
return new FileInputStream(file.toPath().toString());
|
||||
}
|
||||
|
||||
private static final int NP_COLOR = 0xff000000;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<item type="id" name="test_attr1" />
|
||||
</resources>
|
@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<public type="string" name="hello_world" id="0x7f020000" />
|
||||
<public type="xml" name="ww_box_styles_schema" id="0x7f1500df" />
|
||||
</resources>
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="test">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="person" type="xs:string"/>
|
||||
<xs:element name="address">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="address" type="xs:string"/>
|
||||
<xs:element name="city" type="xs:string"/>
|
||||
<xs:element name="country" type="xs:string"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<attr format="integer" name="test_attr1"/>
|
||||
</resources>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<item type="id" name="test_attr1" />
|
||||
</resources>
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="test">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="person" type="xs:string"/>
|
||||
<xs:element name="address">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="address" type="xs:string"/>
|
||||
<xs:element name="city" type="xs:string"/>
|
||||
<xs:element name="country" type="xs:string"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
Binary file not shown.
After Width: | Height: | Size: 230 B |
Binary file not shown.
Reference in New Issue
Block a user