diff --git a/README.md b/README.md index 958051c1b..570e923f8 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ options: --deobf-rewrite-cfg - force to save deobfuscation map --deobf-use-sourcename - use source file name as class name alias --rename-flags - what to rename, comma-separated, 'case' for system case sensitivity, 'valid' for java identifiers, 'printable' characters, 'none' or 'all' + --fs-case-sensitive - treat filesystem as case sensitive, false by default --cfg - save methods control flow graph to dot file --raw-cfg - save methods control flow graph (use raw instructions) -f, --fallback - make simple dump (using goto instead of 'if', 'for', etc) diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java index b79c24449..64c8ee4e0 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java @@ -1,16 +1,11 @@ package jadx.cli; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.api.JadxArgs; import jadx.api.JadxDecompiler; import jadx.core.utils.exceptions.JadxArgsValidateException; -import jadx.core.utils.files.FileUtils; public class JadxCLI { private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class); @@ -32,7 +27,6 @@ public class JadxCLI { static int processAndSave(JadxCLIArgs inputArgs) { JadxArgs args = inputArgs.toJadxArgs(); - args.setFsCaseSensitive(getFsCaseSensitivity(args)); JadxDecompiler jadx = new JadxDecompiler(args); try { jadx.load(); @@ -50,14 +44,4 @@ public class JadxCLI { } return errorsCount; } - - private static boolean getFsCaseSensitivity(JadxArgs args) { - List testDirList = new ArrayList<>(3); - testDirList.add(args.getOutDir()); - testDirList.add(args.getOutDirSrc()); - if (!args.getInputFiles().isEmpty()) { - testDirList.add(args.getInputFiles().get(0)); - } - return FileUtils.isCaseSensitiveFS(testDirList); - } } diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java index 7113557b6..4a3a32d43 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java @@ -85,6 +85,9 @@ public class JadxCLIArgs { @Parameter(names = { "--deobf-use-sourcename" }, description = "use source file name as class name alias") protected boolean deobfuscationUseSourceNameAsAlias = true; + @Parameter(names = { "--fs-case-sensitive" }, description = "treat filesystem as case sensitive, false by default") + protected boolean fsCaseSensitive = false; + @Parameter(names = { "--cfg" }, description = "save methods control flow graph to dot file") protected boolean cfgOutput = false; @@ -190,6 +193,7 @@ public class JadxCLIArgs { args.setRenameCaseSensitive(isRenameCaseSensitive()); args.setRenameValid(isRenameValid()); args.setRenamePrintable(isRenamePrintable()); + args.setFsCaseSensitive(fsCaseSensitive); return args; } @@ -321,8 +325,11 @@ public class JadxCLIArgs { } } - static class RenameConverter implements IStringConverter> { + public boolean isFsCaseSensitive() { + return fsCaseSensitive; + } + static class RenameConverter implements IStringConverter> { private final String paramName; RenameConverter(String paramName) { diff --git a/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java b/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java index 15198ce4f..ad825c8df 100644 --- a/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java @@ -13,13 +13,11 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import org.apache.commons.io.IOCase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -188,52 +186,6 @@ public class FileUtils { } } - /** - * Checks dirs in order, fist success result returned - */ - public static boolean isCaseSensitiveFS(List testDirList) { - for (File dir : testDirList) { - Optional result = isCaseSensitiveFSInternal(dir); - if (result.isPresent()) { - return result.get(); - } - } - return IOCase.SYSTEM.isCaseSensitive(); - } - - public static boolean isCaseSensitiveFS(File testDir) { - Optional result = isCaseSensitiveFSInternal(testDir); - return result.orElseGet(IOCase.SYSTEM::isCaseSensitive); - } - - private static Optional isCaseSensitiveFSInternal(@Nullable File testDir) { - if (testDir != null && testDir.exists() && testDir.isDirectory()) { - File caseCheckUpper = new File(testDir, "CaseCheck"); - File caseCheckLow = new File(testDir, "casecheck"); - try { - makeDirs(testDir); - if (caseCheckUpper.createNewFile()) { - boolean caseSensitive = !caseCheckLow.exists(); - LOG.debug("Filesystem at {} is {}case-sensitive", testDir.getAbsolutePath(), - (caseSensitive ? "" : "NOT ")); - return Optional.of(caseSensitive); - } else { - LOG.debug("Failed to create file: {}", caseCheckUpper.getAbsolutePath()); - } - } catch (Exception e) { - LOG.debug("Failed to detect filesystem case-sensitivity by file creation", e); - } finally { - try { - Files.deleteIfExists(caseCheckUpper.toPath()); - Files.deleteIfExists(caseCheckLow.toPath()); - } catch (Exception e) { - // ignore - } - } - } - return Optional.empty(); - } - public static File toFile(String path) { if (path == null) { return null; diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index a0ed87113..ce265ca18 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -18,7 +18,6 @@ import jadx.api.JadxDecompiler; import jadx.api.JavaClass; import jadx.api.JavaPackage; import jadx.api.ResourceFile; -import jadx.core.utils.files.FileUtils; import jadx.gui.settings.JadxSettings; public class JadxWrapper { @@ -37,8 +36,6 @@ public class JadxWrapper { try { JadxArgs jadxArgs = settings.toJadxArgs(); jadxArgs.setInputFile(file); - // output folder not known yet => use input dir as a best choice - jadxArgs.setFsCaseSensitive(FileUtils.isCaseSensitiveFS(file.getParentFile())); this.decompiler = new JadxDecompiler(jadxArgs); this.decompiler.load(); diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index cd6f88e08..67ddf2a68 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -281,6 +281,10 @@ public class JadxSettings extends JadxCLIArgs { this.inlineAnonymousClasses = inlineAnonymousClasses; } + public void setFsCaseSensitive(boolean fsCaseSensitive) { + this.fsCaseSensitive = fsCaseSensitive; + } + public boolean isAutoStartJobs() { return autoStartJobs; } diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java index c95a35dbe..d48fb80a6 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java @@ -353,6 +353,13 @@ public class JadxSettingsWindow extends JDialog { needReload(); }); + JCheckBox fsCaseSensitive = new JCheckBox(); + fsCaseSensitive.setSelected(settings.isFsCaseSensitive()); + fsCaseSensitive.addItemListener(e -> { + settings.setFsCaseSensitive(e.getStateChange() == ItemEvent.SELECTED); + needReload(); + }); + SettingsGroup other = new SettingsGroup(NLS.str("preferences.decompile")); other.addRow(NLS.str("preferences.threads"), threadsCount); other.addRow(NLS.str("preferences.excludedPackages"), NLS.str("preferences.excludedPackages.tooltip"), @@ -364,6 +371,7 @@ public class JadxSettingsWindow extends JDialog { other.addRow(NLS.str("preferences.respectBytecodeAccessModifiers"), respectBytecodeAccessModifiers); other.addRow(NLS.str("preferences.useImports"), useImports); other.addRow(NLS.str("preferences.inlineAnonymous"), inlineAnonymous); + other.addRow(NLS.str("preferences.fsCaseSensitive"), fsCaseSensitive); other.addRow(NLS.str("preferences.fallback"), fallback); other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode); return other; diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 905a6088d..41580de35 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -93,6 +93,7 @@ preferences.replaceConsts=Replace constants preferences.respectBytecodeAccessModifiers=Respect bytecode access modifiers preferences.useImports=Use import statements preferences.inlineAnonymous=Inline anonymous classes +preferences.fsCaseSensitive=File system is case sensitive preferences.skipResourcesDecode=Don't decode resources preferences.autoSave=Auto save preferences.threads=Processing threads count diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index ab3faf6b4..575ae9c6d 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -93,6 +93,7 @@ preferences.replaceConsts=Reemplazar constantes #preferences.respectBytecodeAccessModifiers= #preferences.useImports= #preferences.inlineAnonymous= +#preferences.fsCaseSensitive= preferences.skipResourcesDecode=No descodificar recursos #preferences.autoSave= preferences.threads=Número de hilos a procesar diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index 81a257f1d..b4da82211 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -93,6 +93,7 @@ preferences.replaceConsts=替换常量 preferences.respectBytecodeAccessModifiers=遵守字节码访问修饰符 preferences.useImports=使用 import 语句 #preferences.inlineAnonymous= +#preferences.fsCaseSensitive= preferences.skipResourcesDecode=不反编译资源文件 #preferences.autoSave= preferences.threads=并行线程数