Projects STRLCPY jadx Commits 57e3dd8f
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/JadxCLI.java
    skipped 31 lines
    32 32   public static int execute(String[] args) {
    33 33   JadxCLIArgs jadxArgs = new JadxCLIArgs();
    34 34   if (jadxArgs.processArgs(args)) {
    35  - return processAndSave(jadxArgs.toJadxArgs());
     35 + return processAndSave(jadxArgs);
    36 36   }
    37 37   return 0;
    38 38   }
    39 39   
    40  - private static int processAndSave(JadxArgs jadxArgs) {
     40 + private static int processAndSave(JadxCLIArgs cliArgs) {
     41 + JadxArgs jadxArgs = cliArgs.toJadxArgs();
    41 42   jadxArgs.setCodeCache(new NoOpCodeCache());
    42 43   jadxArgs.setCodeWriterProvider(SimpleCodeWriter::new);
    43 44   try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) {
    44 45   jadx.load();
    45  - if (LogHelper.getLogLevel() == LogHelper.LogLevelEnum.QUIET) {
    46  - jadx.save();
    47  - } else {
    48  - jadx.save(500, (done, total) -> {
    49  - int progress = (int) (done * 100.0 / total);
    50  - System.out.printf("INFO - progress: %d of %d (%d%%)\r", done, total, progress);
    51  - });
     46 + if (!SingleClassMode.process(jadx, cliArgs)) {
     47 + save(jadx);
    52 48   }
    53 49   int errorsCount = jadx.getErrorsCount();
    54 50   if (errorsCount != 0) {
    skipped 4 lines
    59 55   }
    60 56   }
    61 57   return 0;
     58 + }
     59 + 
     60 + private static void save(JadxDecompiler jadx) {
     61 + if (LogHelper.getLogLevel() == LogHelper.LogLevelEnum.QUIET) {
     62 + jadx.save();
     63 + } else {
     64 + jadx.save(500, (done, total) -> {
     65 + int progress = (int) (done * 100.0 / total);
     66 + System.out.printf("INFO - progress: %d of %d (%d%%)\r", done, total, progress);
     67 + });
     68 + }
    62 69   }
    63 70  }
    64 71   
  • ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
    skipped 39 lines
    40 40   @Parameter(names = { "-s", "--no-src" }, description = "do not decompile source code")
    41 41   protected boolean skipSources = false;
    42 42   
    43  - @Parameter(names = { "--single-class" }, description = "decompile a single class")
     43 + @Parameter(names = { "--single-class" }, description = "decompile a single class, can raw name or an alias")
    44 44   protected String singleClass = null;
     45 + 
     46 + @Parameter(names = { "--single-class-output" }, description = "file or dir for write if decompile a single class")
     47 + protected String singleClassOutput = null;
    45 48   
    46 49   @Parameter(names = { "--output-format" }, description = "can be 'java' or 'json'")
    47 50   protected String outputFormat = "java";
    skipped 179 lines
    227 230   args.setOutputFormat(JadxArgs.OutputFormatEnum.valueOf(outputFormat.toUpperCase()));
    228 231   args.setThreadsCount(threadsCount);
    229 232   args.setSkipSources(skipSources);
    230  - if (singleClass != null) {
    231  - args.setClassFilter(className -> singleClass.equals(className));
    232  - }
    233 233   args.setSkipResources(skipResources);
    234 234   args.setFallbackMode(fallbackMode);
    235 235   args.setShowInconsistentCode(showInconsistentCode);
    skipped 41 lines
    277 277   
    278 278   public String getOutDirRes() {
    279 279   return outDirRes;
     280 + }
     281 + 
     282 + public String getSingleClass() {
     283 + return singleClass;
     284 + }
     285 + 
     286 + public String getSingleClassOutput() {
     287 + return singleClassOutput;
    280 288   }
    281 289   
    282 290   public boolean isSkipResources() {
    skipped 198 lines
  • ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/LogHelper.java
    skipped 57 lines
    58 58   // show progress for all levels except quiet
    59 59   setLevelForClass(JadxCLI.class, Level.INFO);
    60 60   setLevelForClass(JadxDecompiler.class, Level.INFO);
     61 + setLevelForClass(SingleClassMode.class, Level.INFO);
    61 62   }
    62 63   }
    63 64   
    skipped 45 lines
  • ■ ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/SingleClassMode.java
     1 +package jadx.cli;
     2 + 
     3 +import java.io.File;
     4 +import java.util.List;
     5 +import java.util.stream.Collectors;
     6 + 
     7 +import org.slf4j.Logger;
     8 +import org.slf4j.LoggerFactory;
     9 + 
     10 +import jadx.api.ICodeInfo;
     11 +import jadx.api.JadxDecompiler;
     12 +import jadx.core.dex.attributes.AFlag;
     13 +import jadx.core.dex.nodes.ClassNode;
     14 +import jadx.core.dex.visitors.SaveCode;
     15 +import jadx.core.utils.exceptions.JadxRuntimeException;
     16 +import jadx.core.utils.files.FileUtils;
     17 + 
     18 +public class SingleClassMode {
     19 + private static final Logger LOG = LoggerFactory.getLogger(SingleClassMode.class);
     20 + 
     21 + public static boolean process(JadxDecompiler jadx, JadxCLIArgs cliArgs) {
     22 + String singleClass = cliArgs.getSingleClass();
     23 + String singleClassOutput = cliArgs.getSingleClassOutput();
     24 + if (singleClass == null && singleClassOutput == null) {
     25 + return false;
     26 + }
     27 + ClassNode clsForProcess;
     28 + if (singleClass != null) {
     29 + clsForProcess = jadx.getRoot().resolveClass(singleClass);
     30 + if (clsForProcess == null) {
     31 + clsForProcess = jadx.getRoot().getClasses().stream()
     32 + .filter(cls -> cls.getClassInfo().getAliasFullName().equals(singleClass))
     33 + .findFirst().orElse(null);
     34 + }
     35 + if (clsForProcess == null) {
     36 + throw new JadxRuntimeException("Input class not found: " + singleClass);
     37 + }
     38 + if (clsForProcess.contains(AFlag.DONT_GENERATE)) {
     39 + throw new JadxRuntimeException("Input class can't be saved by currect jadx settings (marked as DONT_GENERATE)");
     40 + }
     41 + if (clsForProcess.isInner()) {
     42 + clsForProcess = clsForProcess.getTopParentClass();
     43 + LOG.warn("Input class is inner, parent class will be saved: {}", clsForProcess.getFullName());
     44 + }
     45 + } else {
     46 + // singleClassOutput is set
     47 + // expect only one class to be loaded
     48 + List<ClassNode> classes = jadx.getRoot().getClasses().stream()
     49 + .filter(c -> !c.isInner() && !c.contains(AFlag.DONT_GENERATE))
     50 + .collect(Collectors.toList());
     51 + int size = classes.size();
     52 + if (size == 1) {
     53 + clsForProcess = classes.get(0);
     54 + } else {
     55 + throw new JadxRuntimeException("Found " + size + " classes, single class output can't be used");
     56 + }
     57 + }
     58 + ICodeInfo codeInfo;
     59 + try {
     60 + codeInfo = clsForProcess.decompile();
     61 + } catch (Exception e) {
     62 + throw new JadxRuntimeException("Class decompilation failed", e);
     63 + }
     64 + String fileExt = SaveCode.getFileExtension(jadx.getRoot());
     65 + File out;
     66 + if (singleClassOutput == null) {
     67 + out = new File(jadx.getArgs().getOutDirSrc(), clsForProcess.getClassInfo().getAliasFullPath() + fileExt);
     68 + } else {
     69 + if (singleClassOutput.endsWith(fileExt)) {
     70 + // treat as file name
     71 + out = new File(singleClassOutput);
     72 + } else {
     73 + // treat as directory
     74 + out = new File(singleClassOutput, clsForProcess.getShortName() + fileExt);
     75 + }
     76 + }
     77 + File resultOut = FileUtils.prepareFile(out);
     78 + if (clsForProcess.getClassInfo().hasAlias()) {
     79 + LOG.info("Saving class '{}' (alias: '{}') to file '{}'",
     80 + clsForProcess.getClassInfo().getFullName(), clsForProcess.getFullName(), resultOut.getAbsolutePath());
     81 + } else {
     82 + LOG.info("Saving class '{}' to file '{}'", clsForProcess.getFullName(), resultOut.getAbsolutePath());
     83 + }
     84 + SaveCode.save(codeInfo.getCodeStr(), resultOut);
     85 + return true;
     86 + }
     87 +}
     88 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java
    skipped 10 lines
    11 11  import jadx.api.plugins.utils.ZipSecurity;
    12 12  import jadx.core.dex.attributes.AFlag;
    13 13  import jadx.core.dex.nodes.ClassNode;
     14 +import jadx.core.dex.nodes.RootNode;
    14 15  import jadx.core.utils.exceptions.JadxRuntimeException;
    15 16  import jadx.core.utils.files.FileUtils;
    16 17   
    skipped 20 lines
    37 38   if (cls.root().getArgs().isSkipFilesSave()) {
    38 39   return;
    39 40   }
    40  - String fileName = cls.getClassInfo().getAliasFullPath() + getFileExtension(cls);
     41 + String fileName = cls.getClassInfo().getAliasFullPath() + getFileExtension(cls.root());
    41 42   save(codeStr, dir, fileName);
    42 43   }
    43 44   
    skipped 17 lines
    61 62   }
    62 63   }
    63 64   
    64  - private static String getFileExtension(ClassNode cls) {
    65  - JadxArgs.OutputFormatEnum outputFormat = cls.root().getArgs().getOutputFormat();
     65 + public static String getFileExtension(RootNode root) {
     66 + JadxArgs.OutputFormatEnum outputFormat = root.getArgs().getOutputFormat();
    66 67   switch (outputFormat) {
    67 68   case JAVA:
    68 69   return ".java";
    skipped 10 lines
Please wait...
Page is in error, reload to recover