/* * dex2jar - Tools to work with android .dex and java .class files * 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.tools; import com.googlecode.d2j.Method; import com.googlecode.d2j.dex.BaseDexExceptionHandler; import com.googlecode.d2j.dex.Dex2jar; import com.googlecode.d2j.node.DexMethodNode; import com.googlecode.d2j.reader.DexFileReader; import com.googlecode.d2j.smali.BaksmaliDumper; import com.googlecode.d2j.smali.Smali; import com.googlecode.dex2jar.ir.ET; import org.objectweb.asm.MethodVisitor; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.*; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class BaksmaliBaseDexExceptionHandler extends BaseDexExceptionHandler { public static final String REPORT_MESSAGE = "Please report this file to https://github.com/pxb1988/dex2jar/issues if possible."; private Map exceptionMap = new HashMap<>(); private List fileExceptions = new ArrayList<>(); public boolean hasException() { return exceptionMap.size() > 0 || fileExceptions.size() > 0; } @Override public void handleFileException(Exception e) { super.handleFileException(e); fileExceptions.add(e); } @Override public void handleMethodTranslateException(Method method, DexMethodNode methodNode, MethodVisitor mv, Exception e) { super.handleMethodTranslateException(method, methodNode, mv, e); exceptionMap.put(methodNode, e); } public static String getVersionString() { List vs = new ArrayList<>(); doAddVersion(vs, "dex-reader", DexFileReader.class); doAddVersion(vs, "dex-reader-api", Method.class); doAddVersion(vs, "dex-ir", ET.class); doAddVersion(vs, "d2j-smali", Smali.class); doAddVersion(vs, "d2j-base-cmd", BaseCmd.class); doAddVersion(vs, "dex-tools", Dex2jarCmd.class); doAddVersion(vs, "dex-translator", Dex2jar.class); return vs.toString(); } private static void doAddVersion(List vs, String pkg, Class clz) { try { vs.add(pkg + "-" + clz.getPackage().getImplementationVersion()); } catch (Exception ignore) { // ignored } } public void dump(Path exFile, String[] originalArgs) { String fileName = exFile.getFileName().toString().toLowerCase(); try { if (fileName.endsWith(".zip")) { dumpZip(exFile, originalArgs); } else if (fileName.endsWith(".gz")) { dumGZip(exFile, originalArgs); } else { dumpTxt(exFile, originalArgs); } } catch (IOException e) { throw new RuntimeException(e); } } private void dumpTxt(Path exFile, String[] originalArgs) throws IOException { try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(Files .newOutputStream(exFile), StandardCharsets.UTF_8))) { dumpTxt0(writer, originalArgs); } } private void dumGZip(Path exFile, String[] originalArgs) throws IOException { try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files .newOutputStream(exFile)), StandardCharsets.UTF_8))) { dumpTxt0(writer, originalArgs); } } private void dumpTxt0(BufferedWriter writer, String[] originalArgs) throws IOException { dumpSummary(originalArgs, writer); int i = 0; for (Map.Entry e : exceptionMap.entrySet()) { DexMethodNode dexMethodNode = e.getKey(); Exception ex = e.getValue(); writer.newLine(); writer.write("================= " + i++ + " ==================="); writer.newLine(); dumpMethod(writer, dexMethodNode, ex); } } public void dumpZip(Path exFile, String[] originalArgs) throws IOException { try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(exFile))) { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos, StandardCharsets.UTF_8)); zos.putNextEntry(new ZipEntry("summary.txt")); dumpTxt0(writer, originalArgs); zos.closeEntry(); zos.flush(); } } // dump each method private void dumpMethod(BufferedWriter writer, DexMethodNode dexMethodNode, Exception ex) throws IOException { writer.append(dexMethodNode.method.toString()); writer.newLine(); writer.flush(); ex.printStackTrace(new PrintWriter(writer, true)); writer.newLine(); try { new BaksmaliDumper().baksmaliMethod(dexMethodNode, writer); } catch (Exception e) { // https://github.com/pxb1988/dex2jar/issues/500 // dump out the exception PrintWriter s = new PrintWriter(writer); e.printStackTrace(s); s.flush(); } writer.flush(); } // dump summary: timestamp, version, cmdline private void dumpSummary(String[] originalArgs, BufferedWriter writer) throws IOException { writer.write("#This file is generated by dex2jar"); writer.newLine(); writer.write(REPORT_MESSAGE); writer.newLine(); writer.newLine(); if (fileExceptions.size() > 0) { writer.append(String.format("There are %d fails.", fileExceptions.size())); writer.newLine(); } if (exceptionMap.size() > 0) { writer.append(String.format("There are %d methods fail to translate.", exceptionMap.size())); writer.newLine(); } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); writer.append(sdf.format(new Date())); writer.newLine(); writer.append("version: "); writer.append(getVersionString()); writer.newLine(); writer.append("cmdline: "); writer.append(Arrays.asList(originalArgs).toString()); writer.newLine(); writer.append("env:"); writer.newLine(); Properties properties = System.getProperties(); for (String key : properties.stringPropertyNames()) { if (key.startsWith("java.") && !key.toLowerCase().contains("pass")) { writer.append(key).append(": ").append(properties.getProperty(key)); writer.newLine(); } } PrintWriter p = new PrintWriter(writer, true); for (Exception ex : fileExceptions) { ex.printStackTrace(p); } writer.flush(); } }