/**
* Copyright 2011 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package brut.androlib.src;
import brut.androlib.AndrolibException;
import org.jf.baksmali.baksmali;
import org.jf.dexlib.Code.Analysis.ClassPath;
import org.jf.dexlib.DexFile;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public class SmaliDecoder {
public static void decode(File apkFile, File outDir, boolean debug, String debugLinePrefix,
boolean bakdeb) throws AndrolibException {
new SmaliDecoder(apkFile, outDir, debug, debugLinePrefix, bakdeb).decode();
}
private SmaliDecoder(File apkFile, File outDir, boolean debug, String debugLinePrefix,
boolean bakdeb) {
mApkFile = apkFile;
mOutDir = outDir.toPath();
mDebug = debug;
mDebugLinePrefix = debugLinePrefix;
mBakDeb = bakdeb;
}
private void decode() throws AndrolibException {
try {
ClassPath.dontLoadClassPath = mDebug;
baksmali.disassembleDexFile(mApkFile.getAbsolutePath(),
new DexFile(mApkFile), false, mOutDir.toAbsolutePath().toString(),
null, null, null, false, true, true, mBakDeb, false, false,
mDebug ? org.jf.baksmali.main.DIFFPRE : 0, false, false, null, false);
if (mDebug) {
Files.walkFileTree(mOutDir, new SmaliFileVisitor());
}
} catch (IOException ex) {
throw new AndrolibException(ex);
}
}
private final File mApkFile;
private final Path mOutDir;
private final boolean mDebug;
private final String mDebugLinePrefix;
private final boolean mBakDeb;
private class SmaliFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = file.getFileName().toString();
if (! fileName.endsWith(".smali")) {
return FileVisitResult.CONTINUE;
}
fileName = fileName.substring(0, fileName.length() - 6);
try (
BufferedReader in = Files.newBufferedReader(file, Charset.defaultCharset());
BufferedWriter out = Files.newBufferedWriter(
file.resolveSibling(fileName + ".java"), Charset.defaultCharset())
) {
TypeName type = TypeName.fromPath(mOutDir.relativize(file.resolveSibling(fileName)));
out.write("package " + type.package_ + "; class " + type.getName(true, true) + " { void a() { int a;");
out.newLine();
String line;
final String debugLinePrefix = mDebugLinePrefix;
while ((line = in.readLine()) != null) {
out.write(debugLinePrefix);
out.write(line);
out.newLine();
}
out.write("}}");
out.newLine();
}
Files.delete(file);
return FileVisitResult.CONTINUE;
}
}
}