From bcc4082af059c59b73567b503a2506d1e7e81225 Mon Sep 17 00:00:00 2001 From: Oliver Degener Date: Sun, 25 Apr 2021 12:48:36 +0200 Subject: [PATCH] #24 Redirect dx log to IntelliJ & stop plugin execution on dx errors --- .../org/ollide/java2smali/Class2DexHelper.kt | 26 +++++++++++---- .../org/ollide/java2smali/DexCompiler.kt | 15 +++------ .../ollide/java2smali/log/LogOutputStream.kt | 32 +++++++++++++++++++ 3 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 src/main/kotlin/org/ollide/java2smali/log/LogOutputStream.kt diff --git a/src/main/kotlin/org/ollide/java2smali/Class2DexHelper.kt b/src/main/kotlin/org/ollide/java2smali/Class2DexHelper.kt index 4d264e3..aa8aae7 100644 --- a/src/main/kotlin/org/ollide/java2smali/Class2DexHelper.kt +++ b/src/main/kotlin/org/ollide/java2smali/Class2DexHelper.kt @@ -1,26 +1,38 @@ package org.ollide.java2smali +import com.android.dx.command.dexer.DxContext import com.android.dx.command.dexer.Main - -import java.io.IOException +import com.intellij.openapi.diagnostic.Logger +import org.apache.log4j.Level +import org.ollide.java2smali.log.LogOutputStream object Class2DexHelper { /** - * Uses the dx tool from the Android Build Tools (19.0.1) to create + * Uses the dx tool from the Android Build Tools to create * a .dex version of a compiled java file (.class) * * @param inputClassFilePaths full paths to the compiled .class file * @param outputDexPath this will be the dex output file's path and name - * @throws IOException + * @return `true` if dx ran successfully, otherwise `false` */ - @Throws(IOException::class) - fun dexClassFile(inputClassFilePaths: Array, outputDexPath: String) { + fun dexClassFile(inputClassFilePaths: Array, outputDexPath: String): Boolean { + val dxContext = DxContext(LogOutputStream(LOG, Level.INFO), LogOutputStream(LOG, Level.ERROR)) + val arguments = Main.Arguments() arguments.outName = outputDexPath arguments.strictNameCheck = false arguments.fileNames = inputClassFilePaths - Main.run(arguments) + return try { + val returnCode = Main(dxContext).runDx(arguments) + returnCode == 0 + } catch (e: Exception) { + LOG.error("Failed to run dx", e) + false + } } + + private val LOG = Logger.getInstance(Class2DexHelper::class.java) + } diff --git a/src/main/kotlin/org/ollide/java2smali/DexCompiler.kt b/src/main/kotlin/org/ollide/java2smali/DexCompiler.kt index f454f07..75a76fd 100644 --- a/src/main/kotlin/org/ollide/java2smali/DexCompiler.kt +++ b/src/main/kotlin/org/ollide/java2smali/DexCompiler.kt @@ -16,7 +16,6 @@ import com.intellij.util.SmartList import com.intellij.util.containers.OrderedSet import com.intellij.util.io.URLUtil import java.io.File -import java.io.IOException import java.nio.file.Paths class DexCompiler(private val vFile: VirtualFile, private val project: Project, private val module: Module) { @@ -59,7 +58,10 @@ class DexCompiler(private val vFile: VirtualFile, private val project: Project, // CLASS -> DEX val targetFiles = getClassFiles(fileOutputDirectory, fileName) - compileDexFile(targetFiles, dexFilePath) + val successfulDex = Class2DexHelper.dexClassFile(targetFiles, dexFilePath) + if (!successfulDex) { + return + } // DEX -> SMALI val outputDir = getSourceRootFile().path @@ -144,15 +146,6 @@ class DexCompiler(private val vFile: VirtualFile, private val project: Project, return OrderedSet(outputPaths) } - private fun compileDexFile(compiledPaths: Array, dexFile: String) { - try { - Class2DexHelper.dexClassFile(compiledPaths, dexFile) - } catch (e: IOException) { - e.printStackTrace() - return - } - } - private fun getSourceRootFile(): VirtualFile { return ProjectRootManager.getInstance(project).fileIndex.getSourceRootForFile(vFile) as VirtualFile } diff --git a/src/main/kotlin/org/ollide/java2smali/log/LogOutputStream.kt b/src/main/kotlin/org/ollide/java2smali/log/LogOutputStream.kt new file mode 100644 index 0000000..a7a3b93 --- /dev/null +++ b/src/main/kotlin/org/ollide/java2smali/log/LogOutputStream.kt @@ -0,0 +1,32 @@ +package org.ollide.java2smali.log + +import com.intellij.openapi.diagnostic.Logger +import org.apache.log4j.Level +import java.io.OutputStream + +/** + * Wraps IntelliJ's [com.intellij.openapi.diagnostic.Logger] as an [java.io.OutputStream]. + */ +class LogOutputStream(private val logger: Logger, private val level: Level) : OutputStream() { + + private var msg = "" + + override fun write(b: Int) { + val bytes = ByteArray(1) + bytes[0] = (b and 0xff).toByte() + msg += String(bytes) + if (msg.endsWith("\n")) { + msg = msg.substring(0, msg.length - 1) + flush() + } + } + + override fun flush() { + if (level === Level.ERROR || level === Level.FATAL) { + logger.error(msg) + } else { + logger.info(msg) + } + msg = "" + } +}