/* * Copyright (c) 2009-2012 Panxiaobo * * 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 com.googlecode.dex2jar.util; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import com.googlecode.dex2jar.DexOpcodes; import com.googlecode.dex2jar.Field; import com.googlecode.dex2jar.Method; import com.googlecode.dex2jar.reader.DexFileReader; import com.googlecode.dex2jar.visitors.DexClassVisitor; import com.googlecode.dex2jar.visitors.DexCodeVisitor; import com.googlecode.dex2jar.visitors.DexFieldVisitor; import com.googlecode.dex2jar.visitors.DexMethodVisitor; import com.googlecode.dex2jar.visitors.EmptyVisitor; /** * @author <a href="mailto:pxb1988@gmail.com">Panxiaobo</a> * @version $Rev$ */ public class Dump extends EmptyVisitor { public interface WriterManager { PrintWriter get(String name); } public static void doData(DexFileReader dexFileReader, File destJar) throws IOException { final ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destJar))); dexFileReader.accept(new Dump(new WriterManager() { @Override public PrintWriter get(String name) { try { String s = name.replace('.', '/') + ".dump.txt"; ZipEntry zipEntry = new ZipEntry(s); zos.putNextEntry(zipEntry); return new PrintWriter(zos) { @Override public void close() { try { zos.closeEntry(); } catch (IOException e) { throw new RuntimeException(e); } } }; } catch (Exception e) { throw new RuntimeException(e); } } })); zos.finish(); zos.close(); } public static void doData(byte[] data, File destJar) throws IOException { doData(new DexFileReader(data), destJar); } public static void doFile(File srcDex) throws IOException { doFile(srcDex, new File(srcDex.getParentFile(), srcDex.getName() + "_dump.jar")); } public static void doFile(File srcDex, File destJar) throws IOException { doData(DexFileReader.readDex(srcDex), destJar); } public static String getAccDes(int acc) { StringBuilder sb = new StringBuilder(); if ((acc & DexOpcodes.ACC_PUBLIC) != 0) { sb.append("public "); } if ((acc & DexOpcodes.ACC_PROTECTED) != 0) { sb.append("protected "); } if ((acc & DexOpcodes.ACC_PRIVATE) != 0) { sb.append("private "); } if ((acc & DexOpcodes.ACC_STATIC) != 0) { sb.append("static "); } if ((acc & DexOpcodes.ACC_ABSTRACT) != 0 && (acc & DexOpcodes.ACC_INTERFACE) == 0) { sb.append("abstract "); } if ((acc & DexOpcodes.ACC_ANNOTATION) != 0) { sb.append("annotation "); } if ((acc & DexOpcodes.ACC_BRIDGE) != 0) { sb.append("bridge "); } if ((acc & DexOpcodes.ACC_ENUM) != 0) { sb.append("enum "); } if ((acc & DexOpcodes.ACC_FINAL) != 0) { sb.append("final "); } if ((acc & DexOpcodes.ACC_INTERFACE) != 0) { sb.append("interace "); } if ((acc & DexOpcodes.ACC_NATIVE) != 0) { sb.append("native "); } if ((acc & DexOpcodes.ACC_STRICT) != 0) { sb.append("strict "); } if ((acc & DexOpcodes.ACC_SYNCHRONIZED) != 0) { sb.append("synchronized "); } if ((acc & DexOpcodes.ACC_TRANSIENT) != 0) { sb.append("transient "); } if ((acc & DexOpcodes.ACC_VARARGS) != 0) { sb.append("varargs "); } if ((acc & DexOpcodes.ACC_VOLATILE) != 0) { sb.append("volatile "); } return sb.toString(); } public static void main(String... args) throws IOException { if (args.length < 2) { System.out.println("Dump in.dexORapk out.dump.jar"); return; } doFile(new File(args[0]), new File(args[1])); } private int class_count = 0; private PrintWriter out; private WriterManager writerManager; /** * @param dfv */ public Dump(WriterManager writerManager) { super(); this.writerManager = writerManager; } public static String toJavaClass(String desc) { switch (desc.charAt(0)) { case 'L': return desc.substring(1, desc.length() - 1).replace('/', '.'); case 'B': return "byte"; case 'S': return "short"; case 'C': return "char"; case 'I': return "int"; case 'J': return "long"; case 'F': return "float"; case 'D': return "double"; case '[': return toJavaClass(desc.substring(1)) + "[]"; } return desc; } StringBuilder deps = new StringBuilder(); @Override public void visitDepedence(String name, byte[] checksum) { deps.append("dep: " + name + ", checksum: "); for (byte element : checksum) { deps.append(String.format("%02x", element)); } deps.append("\n"); } @Override public void visitEnd() { if (deps.length() > 0) { PrintWriter out = writerManager.get("depedence"); out.print(deps.toString()); out.flush(); out.close(); } } /* * (non-Javadoc) * * @see com.googlecode.dex2jar.visitors.DexFileVisitor#visit(int, java.lang.String, java.lang.String, * java.lang.String[]) */ @Override public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) { String javaClassName = toJavaClass(className); out = writerManager.get(javaClassName); out.printf("//class:%04d access:0x%04x\n", class_count++, access_flags); out.print(getAccDes(access_flags)); if ((access_flags & DexOpcodes.ACC_INTERFACE) == 0) { out.print("class "); } out.print(javaClassName); if (superClass != null) { if (!"Ljava/lang/Object;".equals(superClass)) { out.print(" extends "); out.print(toJavaClass(superClass)); } } if (interfaceNames != null && interfaceNames.length > 0) { out.print(" implements "); out.print(toJavaClass(interfaceNames[0])); for (int i = 1; i < interfaceNames.length; i++) { out.print(','); out.print(toJavaClass(interfaceNames[i])); } } out.println(); return new EmptyVisitor() { int field_count = 0; int method_count = 0; @Override public void visitEnd() { out.flush(); out.close(); out = null; super.visitEnd(); } @Override public DexFieldVisitor visitField(int accesFlags, Field field, Object value) { out.printf("//field:%04d access:0x%04x\n", field_count++, accesFlags); out.printf("//%s\n", field); out.printf("%s %s %s", getAccDes(accesFlags), toJavaClass(field.getType()), field.getName()); if (value != null) { out.print('='); out.print(value); } out.println(';'); return null; } @Override public DexMethodVisitor visitMethod(final int accesFlags, final Method method) { out.println(); out.printf("//method:%04d access:0x%04x\n", method_count++, accesFlags); out.printf("//%s\n", method); out.printf("%s%s %s(", getAccDes(accesFlags), toJavaClass(method.getReturnType()), method.getName()); String ps[] = method.getParameterTypes(); if (ps != null && ps.length > 0) { out.print(toJavaClass(ps[0])); for (int i = 1; i < ps.length; i++) { out.print(','); out.print(toJavaClass(ps[i])); } } out.println(')'); return new EmptyVisitor() { @Override public DexCodeVisitor visitCode() { return new DumpDexCodeAdapter((accesFlags & DexOpcodes.ACC_STATIC) != 0, method, out); } }; } }; } }