baksmali.java revision 68564258a316e41cb014f98d2777b5944bf37de3
17faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez/*
27faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * [The "BSD licence"]
37faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * Copyright (c) 2010 Ben Gruver (JesusFreke)
47faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * All rights reserved.
57faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
67faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * Redistribution and use in source and binary forms, with or without
77faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * modification, are permitted provided that the following conditions
87faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * are met:
97faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * 1. Redistributions of source code must retain the above copyright
107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *    notice, this list of conditions and the following disclaimer.
117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * 2. Redistributions in binary form must reproduce the above copyright
127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *    notice, this list of conditions and the following disclaimer in the
137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *    documentation and/or other materials provided with the distribution.
147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * 3. The name of the author may not be used to endorse or promote products
157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *    derived from this software without specific prior written permission.
167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez */
287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezpackage org.jf.baksmali;
307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport com.google.common.collect.ImmutableList;
327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport com.google.common.collect.Iterables;
337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport com.google.common.collect.Lists;
347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport com.google.common.collect.Ordering;
357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.baksmali.Adaptors.ClassDefinition;
367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.dexlib2.analysis.ClassPath;
377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.dexlib2.iface.ClassDef;
387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.dexlib2.iface.DexFile;
397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.dexlib2.util.SyntheticAccessorResolver;
407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.util.ClassFileNameHandler;
417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.jf.util.IndentingWriter;
427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.xml.sax.Attributes;
437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.xml.sax.SAXException;
447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport org.xml.sax.helpers.DefaultHandler;
457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport java.io.*;
477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport java.util.List;
487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport java.util.Map.Entry;
497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport java.util.concurrent.*;
507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport javax.xml.parsers.SAXParser;
527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport javax.xml.parsers.SAXParserFactory;
537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezimport javax.xml.parsers.ParserConfigurationException;
547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezpublic class baksmali {
567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        if (options.registerInfo != 0 || options.deodex) {
597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            try {
607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                Iterable<String> extraClassPathEntries;
617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                if (options.extraClassPathEntries != null) {
627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    extraClassPathEntries = options.extraClassPathEntries;
637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } else {
647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    extraClassPathEntries = ImmutableList.of();
657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                options.classPath = ClassPath.fromClassPath(options.bootClassPathDirs,
687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        Iterables.concat(options.bootClassPathEntries, extraClassPathEntries), dexFile,
697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        options.apiLevel);
707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            } catch (Exception ex) {
717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                System.err.println("\n\nError occurred while loading boot class path files. Aborting.");
727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                ex.printStackTrace(System.err);
737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                return false;
747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        if (options.resourceIdFileEntries != null) {
787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            class PublicHandler extends DefaultHandler {
797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                String prefix = null;
807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                public PublicHandler(String prefix) {
817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    super();
827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    this.prefix = prefix;
837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                public void startElement(String uri, String localName,
867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        String qName, Attributes attr) throws SAXException {
877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    if (qName.equals("public")) {
887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        String type = attr.getValue("type");
897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        String name = attr.getValue("name").replace('.', '_');
907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        Integer public_key = Integer.decode(attr.getValue("id"));
917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        String public_val = new StringBuffer()
927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                            .append(prefix)
937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                            .append(".")
947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                            .append(type)
957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                            .append(".")
967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                            .append(name)
977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                            .toString();
987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        options.resourceIds.put(public_key, public_val);
997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    }
1007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
1017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            };
1027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            for (Entry<String,String> entry: options.resourceIdFileEntries.entrySet()) {
1047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                try {
1057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    SAXParser saxp = SAXParserFactory.newInstance().newSAXParser();
1067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    String prefix = entry.getValue();
1077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    saxp.parse(entry.getKey(), new PublicHandler(prefix));
1087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } catch (ParserConfigurationException e) {
1097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    continue;
1107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } catch (SAXException e) {
1117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    continue;
1127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } catch (IOException e) {
1137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    continue;
1147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
1157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
1167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
1177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        File outputDirectoryFile = new File(options.outputDirectory);
1197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        if (!outputDirectoryFile.exists()) {
1207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            if (!outputDirectoryFile.mkdirs()) {
1217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                System.err.println("Can't create the output directory " + options.outputDirectory);
1227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                return false;
1237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
1247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
1257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file
1277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //name collisions, then we'll use the same name for each class, if the dex file goes through multiple
1287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames
1297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //may still change of course
1307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        List<? extends ClassDef> classDefs = Ordering.natural().sortedCopy(dexFile.getClasses());
1317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        if (!options.noAccessorComments) {
1337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            options.syntheticAccessorResolver = new SyntheticAccessorResolver(classDefs);
1347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
1357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        final ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
1377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        ExecutorService executor = Executors.newFixedThreadPool(options.jobs);
1397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        List<Future<Boolean>> tasks = Lists.newArrayList();
1407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        for (final ClassDef classDef: classDefs) {
1427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            tasks.add(executor.submit(new Callable<Boolean>() {
1437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                @Override public Boolean call() throws Exception {
1447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    return disassembleClass(classDef, fileNameHandler, options);
1457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
1467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }));
1477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
1487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        boolean errorOccurred = false;
1507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        for (Future<Boolean> task: tasks) {
1517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            while(true) {
1527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                try {
1537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    if (!task.get()) {
1547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        errorOccurred = true;
1557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    }
1567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } catch (InterruptedException ex) {
1577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    continue;
1587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } catch (ExecutionException ex) {
1597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    throw new RuntimeException(ex);
1607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
1617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                break;
1627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
1637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
1647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        executor.shutdown();
1667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        return !errorOccurred;
1677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
1687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    private static boolean disassembleClass(ClassDef classDef, ClassFileNameHandler fileNameHandler,
1707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                                            baksmaliOptions options) {
1717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        /**
1727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez         * The path for the disassembly file is based on the package name
1737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez         * The class descriptor will look something like:
1747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez         * Ljava/lang/Object;
1757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez         * Where the there is leading 'L' and a trailing ';', and the parts of the
1767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez         * package name are separated by '/'
1777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez         */
1787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        String classDescriptor = classDef.getType();
1797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //validate that the descriptor is formatted like we expect
1817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        if (classDescriptor.charAt(0) != 'L' ||
1827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                classDescriptor.charAt(classDescriptor.length()-1) != ';') {
1837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class");
1847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            return false;
1857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
1867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        File smaliFile = fileNameHandler.getUniqueFilenameForClass(classDescriptor);
1887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //create and initialize the top level string template
1907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        ClassDefinition classDefinition = new ClassDefinition(options, classDef);
1917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        //write the disassembly
1937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        Writer writer = null;
1947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        try
1957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        {
1967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            File smaliParent = smaliFile.getParentFile();
1977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            if (!smaliParent.exists()) {
1987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                if (!smaliParent.mkdirs()) {
1997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    // check again, it's likely it was created in a different thread
2007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    if (!smaliParent.exists()) {
2017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class");
2027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                        return false;
2037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    }
2047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
2057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
2067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            if (!smaliFile.exists()){
2087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                if (!smaliFile.createNewFile()) {
2097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class");
2107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    return false;
2117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
2127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
2137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter(
2157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    new FileOutputStream(smaliFile), "UTF8"));
2167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            writer = new IndentingWriter(bufWriter);
2187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            classDefinition.writeTo((IndentingWriter)writer);
2197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        } catch (Exception ex) {
2207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            System.err.println("\n\nError occurred while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class");
2217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            ex.printStackTrace();
2227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            // noinspection ResultOfMethodCallIgnored
2237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            smaliFile.delete();
2247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            return false;
2257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
2267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        finally
2277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        {
2287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            if (writer != null) {
2297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                try {
2307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    writer.close();
2317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                } catch (Throwable ex) {
2327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    System.err.println("\n\nError occurred while closing file " + smaliFile.toString());
2337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                    ex.printStackTrace();
2347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez                }
2357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            }
2367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        }
2377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        return true;
2387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
2397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
2407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez