Skip to content

Commit

Permalink
Introduce regexp-based filtering for decompiled file names. Resolves #14
Browse files Browse the repository at this point in the history
  • Loading branch information
kwart committed May 17, 2020
1 parent 46ce9f4 commit fa94a44
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 72 deletions.
67 changes: 35 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,41 @@ Find latest bits in **[GitHub Releases](https://github.com/kwart/jd-cmd/releases
You can use the `jd-cli.bat` (Windows) or `jd-cli` (Linux/Unix) scripts to run the the JAR file.

Usage: java -jar jd-cli.jar [options] [Files to decompile]
Options:
--displayLineNumbers, -n
displays line numbers in decompiled classes
Default: false
--escapeUnicodeCharacters, -eu
escape unicode characters in decompiled classes
Default: false
--help, -h
shows this help
Default: false
--logLevel, -g
takes [level] as parameter and sets it as the CLI log level. Possible
values are: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF
Default: INFO
--outputConsole, -oc
enables output to system output stream
Default: false
--outputDir, -od
takes a [directoryPath] as a parameter and configures a flat DIR output
for this path
--outputDirStructured, -ods
takes a [directoryPath] as a parameter and configures a structured DIR
output for this path
--outputZipFile, -oz
takes a [zipFilePath] as a parameter and configures ZIP output for this
path
--skipResources, -sr
skips processing resources
Default: false
--version, -v
shows the version
Default: false
Options:
--displayLineNumbers, -n
displays line numbers in decompiled classes
Default: false
--escapeUnicodeCharacters, -eu
escape unicode characters in decompiled classes
Default: false
--help, -h
shows this help
Default: false
--logLevel, -g
takes [level] as parameter and sets it as the CLI log level. Possible
values are: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF
Default: INFO
--outputConsole, -oc
enables output to system output stream
Default: false
--outputDir, -od
takes a [directoryPath] as a parameter and configures a flat DIR output
for this path
--outputDirStructured, -ods
takes a [directoryPath] as a parameter and configures a structured DIR
output for this path
--outputZipFile, -oz
takes a [zipFilePath] as a parameter and configures ZIP output for this
path
--pattern, -p
RegExp pattern which the to-be-decompiled file has to match. Not matching
entries are skipped.
--skipResources, -sr
skips processing resources
Default: false
--version, -v
shows the version
Default: false


## Credits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public class CLIArguments implements DecompilerOptions {
converter = LogLevelConverter.class)
private final Level logLevel = Level.INFO;

@Parameter(names = { "--pattern", "-p" }, description =
"RegExp pattern which the to-be-decompiled file has to match. Not matching entries are skipped.")
private final String pattern = null;

public List<String> getFiles() {
return files;
}
Expand Down Expand Up @@ -117,6 +121,10 @@ public Level getLogLevel() {
return logLevel;
}

public String getPattern() {
return pattern;
}

public boolean isOutputPluginSpecified() {
return consoleOut || zipOutFile != null || dirOutFile != null || dirOutFileStructured != null;
}
Expand Down
10 changes: 5 additions & 5 deletions jd-cli/src/main/java/com/github/kwart/jd/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public static void main(String[] args) {

if (file.exists()) {
try {
InputOutputPair inOut = getInOutPlugins(file, outputPlugin);
InputOutputPair inOut = getInOutPlugins(file, outputPlugin, cliArguments.getPattern());
inOut.getJdInput().decompile(javaDecompiler, inOut.getJdOutput());
decompiled = true;
} catch (Exception e) {
Expand Down Expand Up @@ -200,12 +200,12 @@ private static JDOutput initOutput(final CLIArguments cliArguments) {
* @throws NullPointerException
* @throws IOException
*/
public static InputOutputPair getInOutPlugins(final File inputFile, JDOutput outPlugin)
public static InputOutputPair getInOutPlugins(final File inputFile, JDOutput outPlugin, String pattern)
throws NullPointerException, IOException {
JDInput jdIn = null;
JDOutput jdOut = null;
if (inputFile.isDirectory()) {
jdIn = new DirInput(inputFile.getPath());
jdIn = new DirInput(inputFile.getPath(), pattern);
jdOut = new DirOutput(new File(inputFile.getName() + ".src"));
} else {
DataInputStream dis = new DataInputStream(new FileInputStream(inputFile));
Expand All @@ -217,11 +217,11 @@ public static InputOutputPair getInOutPlugins(final File inputFile, JDOutput out
}
switch (magic) {
case JavaDecompilerConstants.MAGIC_NR_CLASS_FILE:
jdIn = new ClassFileInput(inputFile.getPath());
jdIn = new ClassFileInput(inputFile.getPath(), pattern);
jdOut = new PrintStreamOutput(System.out);
break;
case JavaDecompilerConstants.MAGIC_NR_ZIP_FILE:
jdIn = new ZipFileInput(inputFile.getPath());
jdIn = new ZipFileInput(inputFile.getPath(), pattern);
String decompiledZipName = inputFile.getName();
int suffixPos = decompiledZipName.lastIndexOf(".");
if (suffixPos >= 0) {
Expand Down
19 changes: 10 additions & 9 deletions jd-cli/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<configuration debug="false">
<configuration debug="false">

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
13 changes: 13 additions & 0 deletions jd-lib/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@
<artifactId>jd-core</artifactId>
<version>${jd.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,35 @@ public abstract class AbstractFileJDInput implements JDInput {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileJDInput.class);

protected final File file;
private final String pattern;

/**
* Constructor based on an existing file path.
*
* @param filePath path to input file
* @throws IllegalArgumentException path doesn't denote an existing file
*/
public AbstractFileJDInput(final String filePath) throws IllegalArgumentException {
LOGGER.trace("Creating JDInput instance for file {}", filePath);
public AbstractFileJDInput(String filePath) throws IllegalArgumentException {
this(filePath, null);
}

public AbstractFileJDInput(String filePath, String pattern) throws IllegalArgumentException {
LOGGER.trace("Creating JDInput instance for file {} and pattern {}", filePath, pattern);
this.pattern = pattern == null ? pattern : (".*" + pattern + ".*");
file = new File(filePath);
if (!file.exists()) {
throw new IllegalArgumentException("Path doesn't denote an existing file.");
}
}

/**
* Returns {@code true} when a pattern is configured and given path doesn't match it.
*/
protected boolean skipThePath(String path) {
boolean skip = pattern != null && path != null && !path.matches(pattern);
if (skip) {
LOGGER.debug("Skipping the path {} as it doesn't match the pattern {}", path, pattern);
}
return skip;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public ClassFileInput(String path) {
super(path);
}

public ClassFileInput(String filePath, String pattern) throws IllegalArgumentException {
super(filePath, pattern);
}

/*
* (non-Javadoc)
*
Expand All @@ -49,8 +53,11 @@ public void decompile(JavaDecompiler javaDecompiler, JDOutput jdOutput) {
return;
}

jdOutput.init(javaDecompiler.getOptions(), "");
final String name = file.getName();
if (skipThePath(name)) {
return;
}
jdOutput.init(javaDecompiler.getOptions(), "");
LOGGER.debug("Decompiling single class file {}", name);
String nameWithoutClassSfx = IOUtils.isClassFile(name) ? IOUtils.cutClassSuffix(name) : name;
jdOutput.processClass(nameWithoutClassSfx, javaDecompiler.decompileClass(new FileLoader(), file.getPath()));
Expand Down
11 changes: 9 additions & 2 deletions jd-lib/src/main/java/com/github/kwart/jd/input/DirInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ public class DirInput extends AbstractFileJDInput {
private static final Logger LOGGER = LoggerFactory.getLogger(DirInput.class);
private final FileLoader fileLoader;

public DirInput(String path) {
super(path);
public DirInput(String path, String pattern) throws IllegalArgumentException {
super(path, pattern);
if (!file.isDirectory()) {
throw new IllegalArgumentException("Path doesn't denote a directory.");
}
this.fileLoader = new FileLoader(path);
}

public DirInput(String path) {
this(path, null);
}

@Override
public void decompile(JavaDecompiler javaDecompiler, JDOutput jdOutput) {
if (javaDecompiler == null || jdOutput == null) {
Expand All @@ -70,6 +74,9 @@ private void processFile(JavaDecompiler javaDecompiler, JDOutput jdOutput, Strin
processFile(javaDecompiler, jdOutput, pathPrefix + fileName + "/", f);
}
} else {
if (skipThePath(nameWithPath)) {
return;
}
if (IOUtils.isClassFile(fileName)) {
if (IOUtils.isInnerClass(fileName)) {
// don't handle inner classes
Expand Down
14 changes: 11 additions & 3 deletions jd-lib/src/main/java/com/github/kwart/jd/input/ZipFileInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ public class ZipFileInput extends AbstractFileJDInput {
private static final Logger LOGGER = LoggerFactory.getLogger(ZipFileInput.class);

/**
* Constructor which takes
*
* @param path
* Constructor.
*/
public ZipFileInput(String path) {
super(path);
}

/**
* Constructor.
*/
public ZipFileInput(String filePath, String pattern) throws IllegalArgumentException {
super(filePath, pattern);
}

/**
* Parses all entres in the zip and decompiles it writing results to {@link JDOutput} instance.
*
Expand All @@ -73,6 +78,9 @@ public void decompile(JavaDecompiler javaDecompiler, JDOutput jdOutput) {
while ((entry = zis.getNextEntry()) != null) {
if (!entry.isDirectory()) {
final String entryName = entry.getName();
if (skipThePath(entryName)) {
continue;
}
if (IOUtils.isClassFile(entryName)) {
if (IOUtils.isInnerClass(entryName)) {
// don't handle inner classes
Expand Down
60 changes: 42 additions & 18 deletions jd-lib/src/test/java/com/github/kwart/jd/JavaDecompilerTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.kwart.jd;

import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -28,14 +29,32 @@
*/
public class JavaDecompilerTest {

private static final DecompilerOptions DC_OPTS = new DecompilerOptions() {

@Override
public boolean isSkipResources() {
return false;
}

@Override
public boolean isEscapeUnicodeCharacters() {
return false;
}

@Override
public boolean isDisplayLineNumbers() {
return false;
}
};

/**
* Temporary folder.
*/
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();

@Test
public void test() throws LoaderException, IOException {
public void basicTest() throws LoaderException, IOException {
JDInput input = new DirInput("target/test-classes");
File tmpRootFolder = temporaryFolder.getRoot();
File tmpFolder = new File(tmpRootFolder, "flat");
Expand All @@ -44,28 +63,33 @@ public void test() throws LoaderException, IOException {
outPlugins.add(new DirOutput(tmpFolder.getAbsoluteFile()));
outPlugins.add(new StructuredDirOutput(tmpStructuredFolder.getAbsoluteFile()));
JDOutput output = new MultiOutput(outPlugins);
JavaDecompiler decompiler = new JavaDecompiler(new DecompilerOptions() {

@Override
public boolean isSkipResources() {
return false;
}

@Override
public boolean isEscapeUnicodeCharacters() {
return false;
}

@Override
public boolean isDisplayLineNumbers() {
return false;
}
});
JavaDecompiler decompiler = new JavaDecompiler(DC_OPTS);
input.decompile(decompiler, output);
assertDecompiled(tmpFolder);
assertDecompiled(new File(tmpStructuredFolder, "test-classes"));
}

@Test
public void patternNotMatchingTest() throws LoaderException, IOException {
JDInput input = new DirInput("target/test-classes", "Not.*Matching");
File tmpFolder = temporaryFolder.getRoot();
JDOutput output = new DirOutput(tmpFolder.getAbsoluteFile());
JavaDecompiler decompiler = new JavaDecompiler(DC_OPTS);
input.decompile(decompiler, output);
File decompiledFile = new File(tmpFolder, "com/github/kwart/jd/HelloWorld.java");
assertFalse(decompiledFile.isFile());
}

@Test
public void patternMatchingTest() throws LoaderException, IOException {
JDInput input = new DirInput("target/test-classes", "jd.Hello.*World\\.");
File tmpFolder = temporaryFolder.getRoot();
JDOutput output = new DirOutput(tmpFolder.getAbsoluteFile());
JavaDecompiler decompiler = new JavaDecompiler(DC_OPTS);
input.decompile(decompiler, output);
assertDecompiled(tmpFolder);
}

private void assertDecompiled(File outputFolder) throws IOException {
File decompiledFile = new File(outputFolder, "com/github/kwart/jd/HelloWorld.java");
assertTrue(decompiledFile.isFile());
Expand Down
Loading

0 comments on commit fa94a44

Please sign in to comment.