pxb.android.dex2jar.dump.Dump.java Source code

Java tutorial

Introduction

Here is the source code for pxb.android.dex2jar.dump.Dump.java

Source

/*
 * Copyright (c) 2009-2010 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 pxb.android.dex2jar.dump;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
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.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ProxyOutputStream;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import pxb.android.dex2jar.Field;
import pxb.android.dex2jar.Method;
import pxb.android.dex2jar.reader.DexFileReader;
import pxb.android.dex2jar.visitors.DexClassAdapter;
import pxb.android.dex2jar.visitors.DexClassVisitor;
import pxb.android.dex2jar.visitors.DexCodeVisitor;
import pxb.android.dex2jar.visitors.DexFieldVisitor;
import pxb.android.dex2jar.visitors.DexFileVisitor;
import pxb.android.dex2jar.visitors.DexMethodAdapter;
import pxb.android.dex2jar.visitors.DexMethodVisitor;
import pxb.android.dex2jar.visitors.EmptyVisitor;

/**
 * @author Panxiaobo [pxb1988@126.com]
 * @version $Id$
 */
public class Dump implements DexFileVisitor {
    private int class_count = 0;
    private DexFileVisitor dfv;
    private PrintWriter out;

    public interface WriterManager {
        PrintWriter get(String name);
    }

    public static String getAccDes(int acc) {
        StringBuilder sb = new StringBuilder();
        if ((acc & Opcodes.ACC_PUBLIC) != 0) {
            sb.append("public ");
        }
        if ((acc & Opcodes.ACC_PROTECTED) != 0) {
            sb.append("protected ");
        }
        if ((acc & Opcodes.ACC_PRIVATE) != 0) {
            sb.append("private ");
        }
        if ((acc & Opcodes.ACC_STATIC) != 0) {
            sb.append("static ");
        }
        if ((acc & Opcodes.ACC_ABSTRACT) != 0 && (acc & Opcodes.ACC_INTERFACE) == 0) {
            sb.append("abstract ");
        }
        if ((acc & Opcodes.ACC_ANNOTATION) != 0) {
            sb.append("annotation ");
        }
        if ((acc & Opcodes.ACC_BRIDGE) != 0) {
            sb.append("bridge ");
        }
        if ((acc & Opcodes.ACC_DEPRECATED) != 0) {
            sb.append("deprecated ");
        }
        if ((acc & Opcodes.ACC_ENUM) != 0) {
            sb.append("enum ");
        }
        if ((acc & Opcodes.ACC_FINAL) != 0) {
            sb.append("final ");
        }
        if ((acc & Opcodes.ACC_INTERFACE) != 0) {
            sb.append("interace ");
        }
        if ((acc & Opcodes.ACC_NATIVE) != 0) {
            sb.append("native ");
        }
        if ((acc & Opcodes.ACC_STRICT) != 0) {
            sb.append("strict ");
        }
        if ((acc & Opcodes.ACC_SYNCHRONIZED) != 0) {
            sb.append("synchronized ");
        }
        if ((acc & Opcodes.ACC_TRANSIENT) != 0) {
            sb.append("transient ");
        }
        if ((acc & Opcodes.ACC_VARARGS) != 0) {
            sb.append("varargs ");
        }
        if ((acc & Opcodes.ACC_VOLATILE) != 0) {
            sb.append("volatile ");
        }
        return sb.toString();
    }

    /**
     * @param dfv
     */
    public Dump(DexFileVisitor dfv, WriterManager writerManager) {
        super();
        this.dfv = dfv;
        this.writerManager = writerManager;
    }

    WriterManager writerManager;

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexFileVisitor#visit(int, java.lang.String, java.lang.String,
     * java.lang.String[])
     */
    public DexClassVisitor visit(int access_flags, String className, String superClass, String... interfaceNames) {

        String javaClassName = Type.getType(className).getClassName();
        out = writerManager.get(javaClassName);
        out.printf("//class:%04d  access:0x%04x\n", class_count++, access_flags);
        out.print(getAccDes(access_flags));
        if ((access_flags & Opcodes.ACC_INTERFACE) == 0) {
            out.print("class ");
        }
        out.print(javaClassName);

        if (!"Ljava/lang/Object;".equals(superClass)) {
            out.print(" extends ");
            out.print(Type.getType(superClass).getClassName());
        }
        if (interfaceNames != null && interfaceNames.length > 0) {
            out.print(" implements ");
            out.print(Type.getType(interfaceNames[0]).getClassName());
            for (int i = 1; i < interfaceNames.length; i++) {
                out.print(',');
                out.print(Type.getType(interfaceNames[i]).getClassName());
            }
        }
        out.println();
        DexClassVisitor dcv = dfv.visit(access_flags, className, superClass, interfaceNames);
        if (dcv == null)
            return null;
        return new DexClassAdapter(dcv) {

            public DexFieldVisitor visitField(Field field, Object value) {
                out.printf("//field:%04d  access:0x%04x\n", field_count++, field.getAccessFlags());
                out.printf("//%s\n", field);
                out.printf("%s %s %s", getAccDes(field.getAccessFlags()),
                        Type.getType(field.getType()).getClassName(), field.getName());
                if (value != null) {
                    out.print('=');
                    out.print(value);
                }
                out.println(';');

                return dcv.visitField(field, value);
            }

            @Override
            public void visitEnd() {
                out.flush();
                out.close();
                out = null;
                super.visitEnd();
            }

            int method_count = 0;
            int field_count = 0;

            public DexMethodVisitor visitMethod(final Method method) {
                out.println();
                out.printf("//method:%04d  access:0x%04x\n", method_count++, method.getAccessFlags());
                out.printf("//%s\n", method);

                out.printf("%s%s %s(", getAccDes(method.getAccessFlags()),
                        Type.getType(method.getType().getReturnType()).getClassName(), method.getName());
                String ps[] = method.getType().getParameterTypes();
                if (ps != null && ps.length > 0) {
                    out.print(Type.getType(ps[0]).getClassName());
                    for (int i = 1; i < ps.length; i++) {
                        out.print(',');
                        out.print(Type.getType(ps[i]).getClassName());
                    }
                }
                out.println(')');

                DexMethodVisitor dmv = dcv.visitMethod(method);
                if (dmv == null) {
                    return null;
                }
                return new DexMethodAdapter(dmv) {
                    public DexCodeVisitor visitCode() {
                        DexCodeVisitor dcv = mv.visitCode();
                        if (dcv == null)
                            return null;
                        return new DumpDexCodeAdapter(dcv, method, out);
                    }
                };
            }
        };
    }

    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]));
    }

    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 {
        byte[] data = FileUtils.readFileToByteArray(srcDex);
        // checkMagic
        if ("dex".equals(new String(data, 0, 3))) {// dex
            doData(data, destJar);
        } else if ("PK".equals(new String(data, 0, 2))) {// ZIP
            ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(data));
            for (ZipEntry entry = zis.getNextEntry(); entry != null; entry = zis.getNextEntry()) {
                if (entry.getName().equals("classes.dex")) {
                    data = IOUtils.toByteArray(zis);
                    doData(data, destJar);
                }
            }
        } else {
            throw new RuntimeException("the src file not a .dex file or a zip file");
        }
    }

    public static void doData(byte[] data, File destJar) throws IOException {
        final ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destJar)));
        new DexFileReader(data).accept(new Dump(new EmptyVisitor(), new WriterManager() {

            public PrintWriter get(String name) {
                try {
                    String s = name.replace('.', '/') + ".dump.txt";
                    ZipEntry zipEntry = new ZipEntry(s);
                    zos.putNextEntry(zipEntry);
                    return new PrintWriter(new ProxyOutputStream(zos) {
                        @Override
                        public void close() throws IOException {
                            zos.closeEntry();
                        }
                    });
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }));
        zos.finish();
        zos.close();
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexFileVisitor#visitEnd()
     */
    public void visitEnd() {
        dfv.visitEnd();
    }

}