Translating Java to Smali is:
Java -(javac)-> Java bytecode -(dx)-> Dex bytecode -(baksmali)-> Smali
If you don't already have it, download the Android SDK.
From Eclipse
Since your code calls this.getAssets()
, it needs to be inside of an Activity class. If you don't already have Eclipse setup to build Android projects, you should start here: Setting up the ADT Bundle. Once it's setup, create a new Android project. Then, add this code to a method in the main activity. Something like this:
public void copyAssets() throws IOException {
InputStream stream = null;
OutputStream output = null;
for (String fileName : this.getAssets().list("www")) {
stream = this.getAssets().open("directoryName/" + fileName);
output = new BufferedOutputStream(new FileOutputStream("/mnt/sdcard/www/" + fileName));
byte data[] = new byte[1024];
int count;
while ((count = stream.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
stream.close();
stream = null;
output = null;
}
}
Then, export the project to an APK. Finally, baksmali the APK to get your Smali. It will have to be added to an Activity class, or something with access to this.getResources()
. The Smali looks like:
.method public copyAssets()V
.registers 13
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/io/IOException;
}
.end annotation
.prologue
const/4 v6, 0x0
.line 41
const/4 v4, 0x0
.line 42
.local v4, "stream":Ljava/io/InputStream;
const/4 v3, 0x0
.line 44
.local v3, "output":Ljava/io/OutputStream;
invoke-virtual {p0}, Lcom/lookout/sauronprobe/MainActivity;->getAssets()Landroid/content/res/AssetManager;
move-result-object v5
const-string v7, "www"
invoke-virtual {v5, v7}, Landroid/content/res/AssetManager;->list(Ljava/lang/String;)[Ljava/lang/String;
move-result-object v7
array-length v8, v7
move v5, v6
:goto_f
if-lt v5, v8, :cond_12
.line 62
return-void
.line 44
:cond_12
aget-object v2, v7, v5
.line 45
.local v2, "fileName":Ljava/lang/String;
invoke-virtual {p0}, Lcom/lookout/sauronprobe/MainActivity;->getAssets()Landroid/content/res/AssetManager;
move-result-object v9
new-instance v10, Ljava/lang/StringBuilder;
const-string v11, "directoryName/"
invoke-direct {v10, v11}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v10, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v10
invoke-virtual {v9, v10}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
move-result-object v4
.line 46
new-instance v3, Ljava/io/BufferedOutputStream;
.end local v3 # "output":Ljava/io/OutputStream;
new-instance v9, Ljava/io/FileOutputStream;
new-instance v10, Ljava/lang/StringBuilder;
const-string v11, "/mnt/sdcard/www/"
invoke-direct {v10, v11}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v10, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v10
invoke-direct {v9, v10}, Ljava/io/FileOutputStream;-><init>(Ljava/lang/String;)V
invoke-direct {v3, v9}, Ljava/io/BufferedOutputStream;-><init>(Ljava/io/OutputStream;)V
.line 48
.restart local v3 # "output":Ljava/io/OutputStream;
const/16 v9, 0x400
new-array v1, v9, [B
.line 51
.local v1, "data":[B
:goto_48
invoke-virtual {v4, v1}, Ljava/io/InputStream;->read([B)I
move-result v0
.local v0, "count":I
const/4 v9, -0x1
if-ne v0, v9, :cond_5d
.line 55
invoke-virtual {v3}, Ljava/io/OutputStream;->flush()V
.line 56
invoke-virtual {v3}, Ljava/io/OutputStream;->close()V
.line 57
invoke-virtual {v4}, Ljava/io/InputStream;->close()V
.line 59
const/4 v4, 0x0
.line 60
const/4 v3, 0x0
.line 44
add-int/lit8 v5, v5, 0x1
goto :goto_f
.line 52
:cond_5d
invoke-virtual {v3, v1, v6, v0}, Ljava/io/OutputStream;->write([BII)V
goto :goto_48
.end method
.method protected onCreate(Landroid/os/Bundle;)V
.registers 6
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
.line 24
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 25
const/high16 v1, 0x7f030000
invoke-virtual {p0, v1}, Lcom/lookout/sauronprobe/MainActivity;->setContentView(I)V
.line 27
invoke-static {}, Lcom/lookout/sauronprobe/MonitorHub;->instance()Lcom/lookout/sauronprobe/MonitorHub;
move-result-object v0
.line 28
.local v0, "hub":Lcom/lookout/sauronprobe/MonitorHub;
invoke-virtual {v0}, Lcom/lookout/sauronprobe/MonitorHub;->start()V
.line 30
new-instance v1, Landroid/content/Intent;
sget-object v2, Lcom/lookout/sauronprobe/Sauron;->instance:Landroid/app/Application;
const-class v3, Lcom/lookout/sauronprobe/telemetry/mq/MessagingService;
invoke-direct {v1, v2, v3}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
invoke-virtual {p0, v1}, Lcom/lookout/sauronprobe/MainActivity;->startService(Landroid/content/Intent;)Landroid/content/ComponentName;
.line 31
return-void
.end method
It's a lot of work up front, but easy once you've done it or if you already have Eclipse setup.
From Command Line
First, refactor the code so it can stand alone as a static method. It will need one parameter for the context, to get access to getAssets()
. Save it with a file name the same as the class name. In this case, CopyAssets.java. Code looks like this:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
public class CopyAssets {
public static void copyAssets(android.content.Context ctx) throws IOException {
InputStream stream = null;
OutputStream output = null;
for (String fileName : ctx.getAssets().list("www")) {
stream = ctx.getAssets().open("directoryName/" + fileName);
output = new BufferedOutputStream(new FileOutputStream("/mnt/sdcard/www/" + fileName));
byte data[] = new byte[1024];
int count;
while ((count = stream.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
stream.close();
stream = null;
output = null;
}
}
}
Second, ensure you have an Android platform downloaded with the SDK. In this case, I have Android-18 downloaded to ~/android/sdk/platforms. The command to compile is:
javac -cp ~/android/sdk/platforms/android-18/android.jar CopyAssets.java
Then, you'll have a CopyAssets.class. Convert it to a Dex with this command:
dx --dex --no-strict --output copyassets.dex CopyAssets.class
The --no-strict
tells dx
to not worry about file structure.
Finally, convert the Dex file to Smali with baksmali:
baksmali copyassets.dex
You will get Smali with a static method you can easily add. It must be called by first getting the context with Activity.getBaseContext()
. You will get this Smali:
.class public LCopyAssets;
.super Ljava/lang/Object;
.source "CopyAssets.java"
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 11
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static copyAssets(Landroid/content/Context;)V
.registers 11
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/io/IOException;
}
.end annotation
.prologue
const/4 v1, 0x0
.line 13
.line 16
invoke-virtual {p0}, Landroid/content/Context;->getAssets()Landroid/content/res/AssetManager;
move-result-object v0
const-string v2, "www"
invoke-virtual {v0, v2}, Landroid/content/res/AssetManager;->list(Ljava/lang/String;)[Ljava/lang/String;
move-result-object v2
array-length v3, v2
move v0, v1
:goto_d
if-ge v0, v3, :cond_64
aget-object v4, v2, v0
.line 17
invoke-virtual {p0}, Landroid/content/Context;->getAssets()Landroid/content/res/AssetManager;
move-result-object v5
new-instance v6, Ljava/lang/StringBuilder;
invoke-direct {v6}, Ljava/lang/StringBuilder;-><init>()V
const-string v7, "directoryName/"
invoke-virtual {v6, v7}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v6
invoke-virtual {v6, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v6
invoke-virtual {v6}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
invoke-virtual {v5, v6}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
move-result-object v5
.line 18
new-instance v6, Ljava/io/BufferedOutputStream;
new-instance v7, Ljava/io/FileOutputStream;
new-instance v8, Ljava/lang/StringBuilder;
invoke-direct {v8}, Ljava/lang/StringBuilder;-><init>()V
const-string v9, "/mnt/sdcard/www/"
invoke-virtual {v8, v9}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v8
invoke-virtual {v8, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v4
invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v4
invoke-direct {v7, v4}, Ljava/io/FileOutputStream;-><init>(Ljava/lang/String;)V
invoke-direct {v6, v7}, Ljava/io/BufferedOutputStream;-><init>(Ljava/io/OutputStream;)V
.line 20
const/16 v4, 0x400
new-array v4, v4, [B
.line 23
:goto_4d
invoke-virtual {v5, v4}, Ljava/io/InputStream;->read([B)I
move-result v7
const/4 v8, -0x1
if-eq v7, v8, :cond_58
.line 24
invoke-virtual {v6, v4, v1, v7}, Ljava/io/OutputStream;->write([BII)V
goto :goto_4d
.line 27
:cond_58
invoke-virtual {v6}, Ljava/io/OutputStream;->flush()V
.line 28
invoke-virtual {v6}, Ljava/io/OutputStream;->close()V
.line 29
invoke-virtual {v5}, Ljava/io/InputStream;->close()V
.line 16
add-int/lit8 v0, v0, 0x1
goto :goto_d
.line 34
:cond_64
return-void
.end method
Here's a helpful alias for tying this all together:
function func_java2smali() {
if [ -z "${1}" ]; then
echo "usage: java2smali <java file>"
return
fi
filename=$(basename $1 .java)
outDir=$(shasum $1 | awk '{print $1}')
javac -cp ~/android/sdk/platforms/android-18/android.jar $1
dx --dex --no-strict --output=$filename.dex $filename.class
baksmali --sequential-labels --use-locals $filename.dex -o $outDir
cp -R $outDir/**/*.smali .
rm -r $outDir
rm $filename.class
rm $filename.dex
}
alias java2smali=func_java2smali