chore: merge upstream
# Conflicts: # brut.apktool/apktool-lib/build.gradle # build.gradle
This commit is contained in:
commit
bef4bc1a80
|
@ -65,7 +65,7 @@ jobs:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-latest, macOS-latest, windows-latest ]
|
os: [ ubuntu-latest, macOS-latest, windows-latest ]
|
||||||
java: [ 8, 9, 10, 11, 12, 13, 14, 15, 16 ]
|
java: [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
|
|
|
@ -23,11 +23,12 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
dependencies {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath(depends.proguard_gradle) {
|
classpath(depends.proguard_gradle) {
|
||||||
exclude group: 'com.android.tools.build'
|
exclude group: 'com.android.tools.build'
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import org.apache.tools.ant.filters.*
|
||||||
import org.apache.tools.ant.filters.ReplaceTokens
|
|
||||||
|
|
||||||
apply plugin: 'java-library'
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ processResources {
|
||||||
from('src/main/resources/properties') {
|
from('src/main/resources/properties') {
|
||||||
include '**/*.properties'
|
include '**/*.properties'
|
||||||
into 'properties'
|
into 'properties'
|
||||||
filter(ReplaceTokens, tokens: [version: project.apktool_version, gitrev: project.hash])
|
filter(ReplaceTokens, tokens: [version: project.apktool_version, gitrev: project.hash] )
|
||||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||||
}
|
}
|
||||||
from('src/main/resources/') {
|
from('src/main/resources/') {
|
||||||
|
@ -34,12 +33,6 @@ processResources {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation depends.junit
|
|
||||||
|
|
||||||
api project(':brut.j.dir'),
|
|
||||||
project(':brut.j.util'),
|
|
||||||
project(':brut.j.common')
|
|
||||||
|
|
||||||
def androidJar
|
def androidJar
|
||||||
def root = System.getenv('ANDROID_SDK_ROOT')
|
def root = System.getenv('ANDROID_SDK_ROOT')
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
|
@ -52,14 +45,19 @@ dependencies {
|
||||||
|
|
||||||
compileOnly androidJar
|
compileOnly androidJar
|
||||||
|
|
||||||
implementation depends.baksmali,
|
api project(':brut.j.dir')
|
||||||
depends.smali,
|
api project(':brut.j.util')
|
||||||
depends.snakeyaml,
|
api project(':brut.j.common')
|
||||||
depends.xmlpull,
|
|
||||||
depends.guava,
|
|
||||||
depends.commons_lang,
|
|
||||||
depends.commons_io,
|
|
||||||
depends.commons_text
|
|
||||||
|
|
||||||
|
implementation depends.baksmali
|
||||||
|
implementation depends.smali
|
||||||
|
implementation depends.snakeyaml
|
||||||
|
implementation depends.xmlpull
|
||||||
|
implementation depends.guava
|
||||||
|
implementation depends.commons_lang
|
||||||
|
implementation depends.commons_io
|
||||||
|
implementation depends.commons_text
|
||||||
|
|
||||||
|
testImplementation depends.junit
|
||||||
testImplementation depends.xmlunit
|
testImplementation depends.xmlunit
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,16 +177,19 @@ public class Androlib {
|
||||||
|
|
||||||
for (String file : files) {
|
for (String file : files) {
|
||||||
if (isAPKFileNames(file) && unk.getCompressionLevel(file) == 0) {
|
if (isAPKFileNames(file) && unk.getCompressionLevel(file) == 0) {
|
||||||
String ext = "";
|
String extOrFile = "";
|
||||||
if (unk.getSize(file) != 0) {
|
if (unk.getSize(file) != 0) {
|
||||||
ext = FilenameUtils.getExtension(file);
|
extOrFile = FilenameUtils.getExtension(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext.isEmpty() || !NO_COMPRESS_PATTERN.matcher(ext).find()) {
|
if (extOrFile.isEmpty() || !NO_COMPRESS_PATTERN.matcher(extOrFile).find()) {
|
||||||
ext = file;
|
extOrFile = file;
|
||||||
|
if (mAndRes.mResFileMapping.containsKey(extOrFile)) {
|
||||||
|
extOrFile = mAndRes.mResFileMapping.get(extOrFile);
|
||||||
}
|
}
|
||||||
if (!uncompressedFilesOrExts.contains(ext)) {
|
}
|
||||||
uncompressedFilesOrExts.add(ext);
|
if (!uncompressedFilesOrExts.contains(extOrFile)) {
|
||||||
|
uncompressedFilesOrExts.add(extOrFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -839,7 +842,7 @@ public class Androlib {
|
||||||
private final static String APK_DIRNAME = "build/apk";
|
private final static String APK_DIRNAME = "build/apk";
|
||||||
private final static String UNK_DIRNAME = "unknown";
|
private final static String UNK_DIRNAME = "unknown";
|
||||||
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
|
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
|
||||||
"resources.arsc", "AndroidManifest.xml", "res" };
|
"resources.arsc", "AndroidManifest.xml", "res", "r", "R" };
|
||||||
private final static String[] APK_RESOURCES_WITHOUT_RES_FILENAMES = new String[] {
|
private final static String[] APK_RESOURCES_WITHOUT_RES_FILENAMES = new String[] {
|
||||||
"resources.arsc", "AndroidManifest.xml" };
|
"resources.arsc", "AndroidManifest.xml" };
|
||||||
private final static String[] APP_RESOURCES_FILENAMES = new String[] {
|
private final static String[] APP_RESOURCES_FILENAMES = new String[] {
|
||||||
|
|
|
@ -180,6 +180,10 @@ public class ApkDecoder {
|
||||||
if (mode != DECODE_SOURCES_NONE && mode != DECODE_SOURCES_SMALI && mode != DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES) {
|
if (mode != DECODE_SOURCES_NONE && mode != DECODE_SOURCES_SMALI && mode != DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES) {
|
||||||
throw new AndrolibException("Invalid decode sources mode: " + mode);
|
throw new AndrolibException("Invalid decode sources mode: " + mode);
|
||||||
}
|
}
|
||||||
|
if (mDecodeSources == DECODE_SOURCES_NONE && mode == DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES) {
|
||||||
|
LOGGER.info("--only-main-classes cannot be paired with -s/--no-src. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
mDecodeSources = mode;
|
mDecodeSources = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,22 +223,12 @@ final public class AndrolibResources {
|
||||||
ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();
|
ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();
|
||||||
|
|
||||||
attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator().next());
|
attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator().next());
|
||||||
Directory inApk, in = null, out;
|
Directory in, out;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
out = new FileDirectory(outDir);
|
out = new FileDirectory(outDir);
|
||||||
|
in = apkFile.getDirectory();
|
||||||
inApk = apkFile.getDirectory();
|
|
||||||
out = out.createDir("res");
|
out = out.createDir("res");
|
||||||
if (inApk.containsDir("res")) {
|
|
||||||
in = inApk.getDir("res");
|
|
||||||
}
|
|
||||||
if (in == null && inApk.containsDir("r")) {
|
|
||||||
in = inApk.getDir("r");
|
|
||||||
}
|
|
||||||
if (in == null && inApk.containsDir("R")) {
|
|
||||||
in = inApk.getDir("R");
|
|
||||||
}
|
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
|
@ -249,7 +239,7 @@ final public class AndrolibResources {
|
||||||
|
|
||||||
LOGGER.fine("Decoding file-resources...");
|
LOGGER.fine("Decoding file-resources...");
|
||||||
for (ResResource res : pkg.listFiles()) {
|
for (ResResource res : pkg.listFiles()) {
|
||||||
fileDecoder.decode(res, in, out);
|
fileDecoder.decode(res, in, out, mResFileMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.fine("Decoding values */* XMLs...");
|
LOGGER.fine("Decoding values */* XMLs...");
|
||||||
|
@ -973,10 +963,15 @@ final public class AndrolibResources {
|
||||||
path = parentPath.getAbsolutePath() + String.format("%1$sLibrary%1$sapktool%1$sframework", File.separatorChar);
|
path = parentPath.getAbsolutePath() + String.format("%1$sLibrary%1$sapktool%1$sframework", File.separatorChar);
|
||||||
} else if (OSDetection.isWindows()) {
|
} else if (OSDetection.isWindows()) {
|
||||||
path = parentPath.getAbsolutePath() + String.format("%1$sAppData%1$sLocal%1$sapktool%1$sframework", File.separatorChar);
|
path = parentPath.getAbsolutePath() + String.format("%1$sAppData%1$sLocal%1$sapktool%1$sframework", File.separatorChar);
|
||||||
|
} else {
|
||||||
|
String xdgDataFolder = System.getenv("XDG_DATA_HOME");
|
||||||
|
if (xdgDataFolder != null) {
|
||||||
|
path = xdgDataFolder + String.format("%1$sapktool%1$sframework", File.separatorChar);
|
||||||
} else {
|
} else {
|
||||||
path = parentPath.getAbsolutePath() + String.format("%1$s.local%1$sshare%1$sapktool%1$sframework", File.separatorChar);
|
path = parentPath.getAbsolutePath() + String.format("%1$s.local%1$sshare%1$sapktool%1$sframework", File.separatorChar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
File dir = new File(path);
|
File dir = new File(path);
|
||||||
|
|
||||||
|
@ -1030,6 +1025,8 @@ final public class AndrolibResources {
|
||||||
|
|
||||||
public BuildOptions buildOptions;
|
public BuildOptions buildOptions;
|
||||||
|
|
||||||
|
public Map<String, String> mResFileMapping = new HashMap();
|
||||||
|
|
||||||
// TODO: dirty static hack. I have to refactor decoding mechanisms.
|
// TODO: dirty static hack. I have to refactor decoding mechanisms.
|
||||||
public static boolean sKeepBroken = false;
|
public static boolean sKeepBroken = false;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ public class ResResSpec {
|
||||||
this.mId = id;
|
this.mId = id;
|
||||||
String cleanName;
|
String cleanName;
|
||||||
|
|
||||||
|
name = (("(name removed)".equals(name)) ? null : name);
|
||||||
|
|
||||||
ResResSpec resResSpec = type.getResSpecUnsafe(name);
|
ResResSpec resResSpec = type.getResSpecUnsafe(name);
|
||||||
if (resResSpec != null) {
|
if (resResSpec != null) {
|
||||||
cleanName = String.format("APKTOOL_DUPLICATE_%s_%s", type, id.toString());
|
cleanName = String.format("APKTOOL_DUPLICATE_%s_%s", type, id.toString());
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class ResEnumAttr extends ResAttr {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ref != null) {
|
if (ref != null && !ref.referentIsNull()) {
|
||||||
value2 = ref.getReferent().getName();
|
value2 = ref.getReferent().getName();
|
||||||
mItemsCache.put(value, value2);
|
mItemsCache.put(value, value2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,19 @@ public class ARSCDecoder {
|
||||||
nextChunk();
|
nextChunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readOverlaySpec() throws IOException {
|
private void readOverlaySpec() throws AndrolibException, IOException {
|
||||||
|
checkChunkType(Header.XML_TYPE_OVERLAY);
|
||||||
|
String name = mIn.readNullEndedString(128, true);
|
||||||
|
String actor = mIn.readNullEndedString(128, true);
|
||||||
|
LOGGER.fine(String.format("Overlay name: \"%s\", actor: \"%s\")", name, actor));
|
||||||
|
|
||||||
|
while(nextChunk().type == Header.XML_TYPE_OVERLAY_POLICY) {
|
||||||
|
readOverlayPolicySpec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readOverlayPolicySpec() throws AndrolibException, IOException {
|
||||||
|
checkChunkType(Header.XML_TYPE_OVERLAY_POLICY);
|
||||||
/* policyFlags */mIn.skipInt();
|
/* policyFlags */mIn.skipInt();
|
||||||
int count = mIn.readInt();
|
int count = mIn.readInt();
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import brut.directory.DirectoryException;
|
||||||
import brut.util.OSDetection;
|
import brut.util.OSDetection;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -38,10 +39,11 @@ public class ResFileDecoder {
|
||||||
this.mDecoders = decoders;
|
this.mDecoders = decoders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decode(ResResource res, Directory inDir, Directory outDir)
|
public void decode(ResResource res, Directory inDir, Directory outDir, Map<String, String> resFileMapping)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
|
|
||||||
ResFileValue fileValue = (ResFileValue) res.getValue();
|
ResFileValue fileValue = (ResFileValue) res.getValue();
|
||||||
|
String inFilePath = fileValue.toString();
|
||||||
String inFileName = fileValue.getStrippedPath();
|
String inFileName = fileValue.getStrippedPath();
|
||||||
String outResName = res.getFilePath();
|
String outResName = res.getFilePath();
|
||||||
String typeName = res.getResSpec().getType().getName();
|
String typeName = res.getResSpec().getType().getName();
|
||||||
|
@ -56,13 +58,18 @@ public class ResFileDecoder {
|
||||||
outFileName = outResName + ext;
|
outFileName = outResName + ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String outFilePath = "res/" + outFileName;
|
||||||
|
if (!inFilePath.equals(outFilePath)) {
|
||||||
|
resFileMapping.put(inFilePath, outFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeName.equals("raw")) {
|
if (typeName.equals("raw")) {
|
||||||
decode(inDir, inFileName, outDir, outFileName, "raw");
|
decode(inDir, inFilePath, outDir, outFileName, "raw");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeName.equals("font") && !".xml".equals(ext)) {
|
if (typeName.equals("font") && !".xml".equals(ext)) {
|
||||||
decode(inDir, inFileName, outDir, outFileName, "raw");
|
decode(inDir, inFilePath, outDir, outFileName, "raw");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeName.equals("drawable") || typeName.equals("mipmap")) {
|
if (typeName.equals("drawable") || typeName.equals("mipmap")) {
|
||||||
|
@ -77,26 +84,24 @@ public class ResFileDecoder {
|
||||||
// check for raw 9patch images
|
// check for raw 9patch images
|
||||||
for (String extension : RAW_9PATCH_IMAGE_EXTENSIONS) {
|
for (String extension : RAW_9PATCH_IMAGE_EXTENSIONS) {
|
||||||
if (inFileName.toLowerCase().endsWith("." + extension)) {
|
if (inFileName.toLowerCase().endsWith("." + extension)) {
|
||||||
copyRaw(inDir, outDir, inFileName, outFileName);
|
copyRaw(inDir, outDir, inFilePath, outFileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for xml 9 patches which are just xml files
|
// check for xml 9 patches which are just xml files
|
||||||
if (inFileName.toLowerCase().endsWith(".xml")) {
|
if (inFileName.toLowerCase().endsWith(".xml")) {
|
||||||
decode(inDir, inFileName, outDir, outFileName, "xml");
|
decode(inDir, inFilePath, outDir, outFileName, "xml");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
decode(inDir, inFileName, outDir, outFileName, "9patch");
|
decode(inDir, inFilePath, outDir, outFileName, "9patch");
|
||||||
return;
|
return;
|
||||||
} catch (CantFind9PatchChunkException ex) {
|
} catch (CantFind9PatchChunkException ex) {
|
||||||
LOGGER.log(
|
LOGGER.log(Level.WARNING, String.format(
|
||||||
Level.WARNING,
|
"Cant find 9patch chunk in file: \"%s\". Renaming it to *.png.", inFileName
|
||||||
String.format(
|
), ex);
|
||||||
"Cant find 9patch chunk in file: \"%s\". Renaming it to *.png.",
|
|
||||||
inFileName), ex);
|
|
||||||
outDir.removeFile(outFileName);
|
outDir.removeFile(outFileName);
|
||||||
outFileName = outResName + ext;
|
outFileName = outResName + ext;
|
||||||
}
|
}
|
||||||
|
@ -105,23 +110,23 @@ public class ResFileDecoder {
|
||||||
// check for raw image
|
// check for raw image
|
||||||
for (String extension : RAW_IMAGE_EXTENSIONS) {
|
for (String extension : RAW_IMAGE_EXTENSIONS) {
|
||||||
if (inFileName.toLowerCase().endsWith("." + extension)) {
|
if (inFileName.toLowerCase().endsWith("." + extension)) {
|
||||||
copyRaw(inDir, outDir, inFileName, outFileName);
|
copyRaw(inDir, outDir, inFilePath, outFileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!".xml".equals(ext)) {
|
if (!".xml".equals(ext)) {
|
||||||
decode(inDir, inFileName, outDir, outFileName, "raw");
|
decode(inDir, inFilePath, outDir, outFileName, "raw");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decode(inDir, inFileName, outDir, outFileName, "xml");
|
decode(inDir, inFilePath, outDir, outFileName, "xml");
|
||||||
} catch (RawXmlEncounteredException ex) {
|
} catch (RawXmlEncounteredException ex) {
|
||||||
// If we got an error to decode XML, lets assume the file is in raw format.
|
// 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
|
// 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.
|
// XSD files are AXML`d on aapt1, but left in plaintext in aapt2.
|
||||||
decode(inDir, inFileName, outDir, outFileName, "raw");
|
decode(inDir, inFilePath, outDir, outFileName, "raw");
|
||||||
} catch (AndrolibException ex) {
|
} catch (AndrolibException ex) {
|
||||||
LOGGER.log(Level.SEVERE, String.format(
|
LOGGER.log(Level.SEVERE, String.format(
|
||||||
"Could not decode file, replacing by FALSE value: %s",
|
"Could not decode file, replacing by FALSE value: %s",
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class StyledString {
|
||||||
|
|
||||||
public static class Span implements Comparable<Span> {
|
public static class Span implements Comparable<Span> {
|
||||||
private static final MapSplitter ATTRIBUTES_SPLITTER =
|
private static final MapSplitter ATTRIBUTES_SPLITTER =
|
||||||
Splitter.on(';').withKeyValueSeparator(Splitter.on('=').limit(2));
|
Splitter.on(';').omitEmptyStrings().withKeyValueSeparator(Splitter.on('=').limit(2));
|
||||||
|
|
||||||
private final String tag;
|
private final String tag;
|
||||||
private final int firstChar;
|
private final int firstChar;
|
||||||
|
|
|
@ -56,4 +56,18 @@ public class AndResGuardTest extends BaseTest {
|
||||||
File aPng = new File(sTestOrigDir,"res/mipmap-hdpi-v4/a.png");
|
File aPng = new File(sTestOrigDir,"res/mipmap-hdpi-v4/a.png");
|
||||||
assertTrue(aPng.isFile());
|
assertTrue(aPng.isFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkifAndResDecodeRemapsRFolderInRawMode() throws BrutException, IOException {
|
||||||
|
String apk = "issue1170.apk";
|
||||||
|
ApkDecoder apkDecoder = new ApkDecoder(new File(sTmpDir + File.separator + apk));
|
||||||
|
sTestOrigDir = new ExtFile(sTmpDir + File.separator + apk + ".raw.out");
|
||||||
|
|
||||||
|
apkDecoder.setOutDir(new File(sTmpDir + File.separator + apk + ".raw.out"));
|
||||||
|
apkDecoder.setDecodeResources(ApkDecoder.DECODE_RESOURCES_NONE);
|
||||||
|
apkDecoder.decode();
|
||||||
|
|
||||||
|
File aPng = new File(sTestOrigDir,"r/a/a.png");
|
||||||
|
assertTrue(aPng.isFile());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,3 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dependencies {
|
|
||||||
testImplementation depends.junit
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':brut.j.common'),
|
implementation project(':brut.j.common')
|
||||||
project(':brut.j.util'),
|
implementation project(':brut.j.util')
|
||||||
depends.commons_io
|
implementation depends.commons_io
|
||||||
testImplementation depends.junit
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import brut.common.TraversalUnknownFileException;
|
||||||
import brut.util.BrutIO;
|
import brut.util.BrutIO;
|
||||||
import brut.util.OS;
|
import brut.util.OS;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class DirUtil {
|
public class DirUtil {
|
||||||
|
@ -84,14 +85,13 @@ public class DirUtil {
|
||||||
if (in.containsDir(fileName)) {
|
if (in.containsDir(fileName)) {
|
||||||
OS.rmdir(new File(out, fileName));
|
OS.rmdir(new File(out, fileName));
|
||||||
in.getDir(fileName).copyToDir(new File(out, fileName));
|
in.getDir(fileName).copyToDir(new File(out, fileName));
|
||||||
|
} else if (!in.containsDir(fileName) && !in.containsFile(fileName)) {
|
||||||
|
// Skip copies of directories/files not found.
|
||||||
} else {
|
} else {
|
||||||
if (fileName.equals("res") && !in.containsFile(fileName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String cleanedFilename = BrutIO.sanitizeUnknownFile(out, fileName);
|
String cleanedFilename = BrutIO.sanitizeUnknownFile(out, fileName);
|
||||||
File outFile = new File(out, cleanedFilename);
|
File outFile = new File(out, cleanedFilename);
|
||||||
outFile.getParentFile().mkdirs();
|
outFile.getParentFile().mkdirs();
|
||||||
BrutIO.copyAndClose(in.getFileInput(fileName), new FileOutputStream(outFile));
|
BrutIO.copyAndClose(in.getFileInput(fileName), Files.newOutputStream(outFile.toPath()));
|
||||||
}
|
}
|
||||||
} catch (RootUnknownFileException | InvalidUnknownFileException | TraversalUnknownFileException exception) {
|
} catch (RootUnknownFileException | InvalidUnknownFileException | TraversalUnknownFileException exception) {
|
||||||
LOGGER.warning(String.format("Skipping file %s (%s)", fileName, exception.getMessage()));
|
LOGGER.warning(String.format("Skipping file %s (%s)", fileName, exception.getMessage()));
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':brut.j.common'),
|
implementation project(':brut.j.common')
|
||||||
depends.commons_io
|
implementation depends.commons_io
|
||||||
testImplementation depends.junit
|
|
||||||
}
|
}
|
||||||
|
|
30
build.gradle
30
build.gradle
|
@ -18,23 +18,22 @@ import java.nio.charset.StandardCharsets
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
depends = [
|
depends = [
|
||||||
baksmali : 'org.smali:baksmali:2.5.2',
|
baksmali : 'com.github.iBotPeaches.smali:baksmali:403e90375e',
|
||||||
commons_cli : 'commons-cli:commons-cli:1.5.0',
|
commons_cli : 'commons-cli:commons-cli:1.5.0',
|
||||||
commons_io : 'commons-io:commons-io:2.11.0',
|
commons_io : 'commons-io:commons-io:2.11.0',
|
||||||
commons_lang : 'org.apache.commons:commons-lang3:3.12.0',
|
commons_lang : 'org.apache.commons:commons-lang3:3.12.0',
|
||||||
commons_text : 'org.apache.commons:commons-text:1.9',
|
commons_text : 'org.apache.commons:commons-text:1.10.0',
|
||||||
guava : 'com.google.guava:guava:31.0.1-jre',
|
guava : 'com.google.guava:guava:31.0.1-jre',
|
||||||
junit : 'junit:junit:4.13.2',
|
junit : 'junit:junit:4.13.2',
|
||||||
proguard_gradle: 'com.guardsquare:proguard-gradle:7.1.1',
|
proguard_gradle: 'com.guardsquare:proguard-gradle:7.3.0',
|
||||||
snakeyaml : 'org.yaml:snakeyaml:1.29:android',
|
snakeyaml : 'org.yaml:snakeyaml:1.32:android',
|
||||||
smali : 'org.smali:smali:2.5.2',
|
smali : 'com.github.iBotPeaches.smali:smali:403e90375e',
|
||||||
xmlpull : 'xpp3:xpp3:1.1.4c',
|
xmlpull : 'xpp3:xpp3:1.1.4c',
|
||||||
xmlunit : 'xmlunit:xmlunit:1.6',
|
xmlunit : 'xmlunit:xmlunit:1.6',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -49,7 +48,7 @@ def ghPassword = project.findProperty("gpr.key") ?: System.getenv("GITHUB_TOKEN"
|
||||||
apply from: 'gradle/functions.gradle'
|
apply from: 'gradle/functions.gradle'
|
||||||
|
|
||||||
version = '2.7.0'
|
version = '2.7.0'
|
||||||
def suffix = 'SNAPSHOT'
|
def suffix = ''
|
||||||
|
|
||||||
defaultTasks 'build', 'shadowJar', 'proguard'
|
defaultTasks 'build', 'shadowJar', 'proguard'
|
||||||
|
|
||||||
|
@ -97,6 +96,19 @@ allprojects {
|
||||||
"licenseTest"
|
"licenseTest"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
// Obtain baksmali/smali from source builds - https://github.com/iBotPeaches/smali
|
||||||
|
// Remove when official smali releases come out again.
|
||||||
|
maven {
|
||||||
|
url 'https://jitpack.io'
|
||||||
|
content {
|
||||||
|
includeGroup('com.github.iBotPeaches.smali')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -165,10 +177,6 @@ task snapshot {
|
||||||
subprojects {
|
subprojects {
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
testLogging {
|
testLogging {
|
||||||
exceptionFormat = 'full'
|
exceptionFormat = 'full'
|
||||||
|
|
Loading…
Reference in New Issue