-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<idea-plugin version="2"> | ||
<id>org.ollide.java2smali</id> | ||
<name>java2smali</name> | ||
<version>1.0</version> | ||
<vendor email="[email protected]" url="https://github.com/ollide">ollide</vendor> | ||
|
||
<description><![CDATA[ | ||
Simple plugin to easily compile a Java file to smali. | ||
]]></description> | ||
|
||
<change-notes><![CDATA[ | ||
<b>version 1.0</b><br> | ||
initial release | ||
]]> | ||
</change-notes> | ||
|
||
<!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description --> | ||
<idea-version since-build="123.72"/> | ||
|
||
<application-components> | ||
<!-- Add your application components here --> | ||
</application-components> | ||
|
||
<project-components> | ||
<!-- Add your project components here --> | ||
</project-components> | ||
|
||
<actions> | ||
<action id="generateSmaliCode" class="org.ollide.java2smali.GenerateAction" text="Compile to smali" | ||
description="Creates and shows a smali version of this Java file"> | ||
<add-to-group group-id="BuildMenu" anchor="after" relative-to-action="Compile"/> | ||
</action> | ||
</actions> | ||
|
||
<extensions defaultExtensionNs="com.intellij"> | ||
<!-- Add your extensions here --> | ||
</extensions> | ||
</idea-plugin> |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.ollide.java2smali; | ||
|
||
import com.android.dx.command.dexer.Main; | ||
|
||
import java.io.IOException; | ||
|
||
public class Class2DexHelper { | ||
|
||
/** | ||
* Uses the dx tool from the Android Build Tools (19.0.1) to create | ||
* a .dex version of a compiled java file (.class) | ||
* | ||
* @param inputClassFilePath full path to the compiled .class file | ||
* @param outputDexPath this will be the dex output file's path and name | ||
* @throws IOException | ||
*/ | ||
public static void dexClassFile(String inputClassFilePath, String outputDexPath) throws IOException { | ||
Main.Arguments arguments = new Main.Arguments(); | ||
arguments.outName = outputDexPath; | ||
arguments.strictNameCheck = false; | ||
arguments.fileNames = new String[]{inputClassFilePath}; | ||
|
||
Main.run(arguments); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package org.ollide.java2smali; | ||
|
||
import org.jf.baksmali.baksmali; | ||
import org.jf.baksmali.baksmaliOptions; | ||
import org.jf.dexlib2.DexFileFactory; | ||
import org.jf.dexlib2.dexbacked.DexBackedDexFile; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
|
||
public class Dex2SmaliHelper { | ||
|
||
/** | ||
* Uses baksmali, an disassembler for Android's dex format. | ||
* Source code and more information: https://bitbucket.org/JesusFreke/smali/overview | ||
* | ||
* @param dexFilePath | ||
* @param outputDir | ||
* @throws IOException | ||
*/ | ||
public static void disassembleDexFile(String dexFilePath, String outputDir) throws IOException { | ||
DexBackedDexFile dexBackedDexFile = DexFileFactory.loadDexFile(new File(dexFilePath), 19); | ||
baksmaliOptions options = new baksmaliOptions(); | ||
options.outputDirectory = outputDir; | ||
|
||
// default value -1 will lead to an exception | ||
// this setup is copied from Baksmali project | ||
options.jobs = Runtime.getRuntime().availableProcessors(); | ||
if (options.jobs > 6) { | ||
options.jobs = 6; | ||
} | ||
|
||
baksmali.disassembleDexFile(dexBackedDexFile, options); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package org.ollide.java2smali; | ||
|
||
import com.intellij.openapi.actionSystem.AnAction; | ||
import com.intellij.openapi.actionSystem.AnActionEvent; | ||
import com.intellij.openapi.actionSystem.LangDataKeys; | ||
import com.intellij.openapi.actionSystem.PlatformDataKeys; | ||
import com.intellij.openapi.compiler.CompileContext; | ||
import com.intellij.openapi.compiler.CompileStatusNotification; | ||
import com.intellij.openapi.compiler.CompilerManager; | ||
import com.intellij.openapi.editor.Editor; | ||
import com.intellij.openapi.fileEditor.OpenFileDescriptor; | ||
import com.intellij.openapi.module.Module; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.roots.ProjectRootManager; | ||
import com.intellij.openapi.vfs.LocalFileSystem; | ||
import com.intellij.openapi.vfs.VirtualFile; | ||
import com.intellij.psi.PsiClass; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiFile; | ||
import com.intellij.psi.PsiJavaFile; | ||
import com.intellij.psi.util.PsiTreeUtil; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
|
||
public class GenerateAction extends AnAction { | ||
|
||
private static final String CLASS_EXTENSION = ".class"; | ||
private static final String DEX_EXTENSION = ".dex"; | ||
private static final String JAVA_EXTENSION = ".java"; | ||
private static final String SMALI_EXTENSION = ".smali"; | ||
|
||
public void actionPerformed(AnActionEvent e) { | ||
PsiJavaFile javaFile = (PsiJavaFile) getPsiClassFromContext(e).getContainingFile(); | ||
|
||
Project p = e.getProject(); | ||
Module module = ProjectRootManager.getInstance(p).getFileIndex().getModuleForFile(javaFile.getVirtualFile()); | ||
|
||
// Compile the javaFile's module | ||
CompilerCallback compilerCallback = new CompilerCallback(javaFile); | ||
CompilerManager.getInstance(p).compile(module, compilerCallback); | ||
} | ||
|
||
@Override | ||
public void update(AnActionEvent e) { | ||
PsiClass psiClass = getPsiClassFromContext(e); | ||
e.getPresentation().setEnabled(psiClass != null && psiClass.getContainingFile() instanceof PsiJavaFile); | ||
} | ||
|
||
private PsiClass getPsiClassFromContext(AnActionEvent e) { | ||
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE); | ||
Editor editor = e.getData(PlatformDataKeys.EDITOR); | ||
|
||
if (psiFile == null || editor == null) { | ||
return null; | ||
} | ||
|
||
int offset = editor.getCaretModel().getOffset(); | ||
PsiElement elementAt = psiFile.findElementAt(offset); | ||
return PsiTreeUtil.getParentOfType(elementAt, PsiClass.class); | ||
} | ||
|
||
private static VirtualFile getSourceRootFile(PsiFile file) { | ||
return ProjectRootManager.getInstance(file.getProject()).getFileIndex().getSourceRootForFile(file.getVirtualFile()); | ||
} | ||
|
||
/** | ||
* This is the Callback class which is called when the module has been compiled. | ||
*/ | ||
private static class CompilerCallback implements CompileStatusNotification { | ||
|
||
private final PsiJavaFile javaFile; | ||
|
||
public CompilerCallback(PsiJavaFile file) { | ||
this.javaFile = file; | ||
} | ||
|
||
public void finished(boolean b, int i, int i2, CompileContext compileContext) { | ||
VirtualFile[] outputDirectories = compileContext.getAllOutputDirectories(); | ||
if (outputDirectories != null && outputDirectories.length > 0) { | ||
String compileDirPath = outputDirectories[0].getPath(); | ||
String compiledFilePath = getCompiledClassFilePath(compileDirPath); | ||
|
||
String dexFile = compiledFilePath + DEX_EXTENSION; | ||
// CLASS -> DEX | ||
try { | ||
Class2DexHelper.dexClassFile(compiledFilePath, dexFile); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return; | ||
} | ||
|
||
// DEX -> SMALI | ||
String outputDir = getSourceRootFile(javaFile).getPath(); | ||
try { | ||
Dex2SmaliHelper.disassembleDexFile(dexFile, outputDir); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return; | ||
} | ||
|
||
// we've created the smali file in our source file's directory | ||
// refresh directory synchronously to let IDEA detect the file | ||
javaFile.getVirtualFile().getParent().refresh(false, false); | ||
|
||
// get a VirtualFile by the IO path | ||
String smaliPath = javaFile.getVirtualFile().getPath().replace(JAVA_EXTENSION, SMALI_EXTENSION); | ||
VirtualFile virtualDexFile = LocalFileSystem.getInstance().findFileByIoFile(new File(smaliPath)); | ||
if (virtualDexFile == null) { | ||
// create smali file failed | ||
return; | ||
} | ||
|
||
// use the VirtualFile to show the smali file in IDEA editor | ||
OpenFileDescriptor openFileDescriptor = new OpenFileDescriptor(javaFile.getProject(), virtualDexFile); | ||
openFileDescriptor.navigate(true); | ||
} | ||
} | ||
|
||
private String getCompiledClassFilePath(String dirPath) { | ||
String packageName = javaFile.getPackageName(); | ||
String[] packages = packageName.split("\\."); | ||
|
||
StringBuilder sb = new StringBuilder(dirPath); | ||
for (String p : packages) { | ||
sb.append(File.separator); | ||
sb.append(p); | ||
} | ||
sb.append(File.separator); | ||
sb.append(javaFile.getContainingFile().getVirtualFile().getNameWithoutExtension()); | ||
sb.append(CLASS_EXTENSION); | ||
return sb.toString(); | ||
} | ||
} | ||
} |