1735746595fc623181546a08f415efd5215d88657Ben Gruver/*
2735746595fc623181546a08f415efd5215d88657Ben Gruver * Copyright 2016, Google Inc.
3735746595fc623181546a08f415efd5215d88657Ben Gruver * All rights reserved.
4735746595fc623181546a08f415efd5215d88657Ben Gruver *
5735746595fc623181546a08f415efd5215d88657Ben Gruver * Redistribution and use in source and binary forms, with or without
6735746595fc623181546a08f415efd5215d88657Ben Gruver * modification, are permitted provided that the following conditions are
7735746595fc623181546a08f415efd5215d88657Ben Gruver * met:
8735746595fc623181546a08f415efd5215d88657Ben Gruver *
9735746595fc623181546a08f415efd5215d88657Ben Gruver * Redistributions of source code must retain the above copyright
10735746595fc623181546a08f415efd5215d88657Ben Gruver * notice, this list of conditions and the following disclaimer.
11735746595fc623181546a08f415efd5215d88657Ben Gruver * Redistributions in binary form must reproduce the above
12735746595fc623181546a08f415efd5215d88657Ben Gruver * copyright notice, this list of conditions and the following disclaimer
13735746595fc623181546a08f415efd5215d88657Ben Gruver * in the documentation and/or other materials provided with the
14735746595fc623181546a08f415efd5215d88657Ben Gruver * distribution.
15735746595fc623181546a08f415efd5215d88657Ben Gruver * Neither the name of Google Inc. nor the names of its
16735746595fc623181546a08f415efd5215d88657Ben Gruver * contributors may be used to endorse or promote products derived from
17735746595fc623181546a08f415efd5215d88657Ben Gruver * this software without specific prior written permission.
18735746595fc623181546a08f415efd5215d88657Ben Gruver *
19735746595fc623181546a08f415efd5215d88657Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20735746595fc623181546a08f415efd5215d88657Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21735746595fc623181546a08f415efd5215d88657Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22735746595fc623181546a08f415efd5215d88657Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23735746595fc623181546a08f415efd5215d88657Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24735746595fc623181546a08f415efd5215d88657Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25735746595fc623181546a08f415efd5215d88657Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26735746595fc623181546a08f415efd5215d88657Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27735746595fc623181546a08f415efd5215d88657Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28735746595fc623181546a08f415efd5215d88657Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29735746595fc623181546a08f415efd5215d88657Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30735746595fc623181546a08f415efd5215d88657Ben Gruver */
31735746595fc623181546a08f415efd5215d88657Ben Gruver
32735746595fc623181546a08f415efd5215d88657Ben Gruverpackage org.jf.smali;
33735746595fc623181546a08f415efd5215d88657Ben Gruver
34735746595fc623181546a08f415efd5215d88657Ben Gruverimport com.google.common.collect.Lists;
35735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.CommonTokenStream;
36735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.Token;
37735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.TokenSource;
38735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.tree.CommonTree;
39735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.tree.CommonTreeNodeStream;
40735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.jf.dexlib2.Opcodes;
41735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.jf.dexlib2.writer.builder.DexBuilder;
42735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.jf.dexlib2.writer.io.FileDataStore;
43735746595fc623181546a08f415efd5215d88657Ben Gruver
44735746595fc623181546a08f415efd5215d88657Ben Gruverimport javax.annotation.Nonnull;
45735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.File;
46735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.FileInputStream;
47735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.IOException;
48735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.InputStreamReader;
49735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.Arrays;
50735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.LinkedHashSet;
51735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.List;
52735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.Set;
53735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.concurrent.*;
54735746595fc623181546a08f415efd5215d88657Ben Gruver
55735746595fc623181546a08f415efd5215d88657Ben Gruverpublic class Smali {
56735746595fc623181546a08f415efd5215d88657Ben Gruver
57735746595fc623181546a08f415efd5215d88657Ben Gruver    /**
58735746595fc623181546a08f415efd5215d88657Ben Gruver     * Assemble the specified files, using the given options
59735746595fc623181546a08f415efd5215d88657Ben Gruver     *
60735746595fc623181546a08f415efd5215d88657Ben Gruver     * @param options a SmaliOptions object with the options to run smali with
61735746595fc623181546a08f415efd5215d88657Ben Gruver     * @param input The files/directories to process
62735746595fc623181546a08f415efd5215d88657Ben Gruver     * @return true if assembly completed with no errors, or false if errors were encountered
63735746595fc623181546a08f415efd5215d88657Ben Gruver     */
64735746595fc623181546a08f415efd5215d88657Ben Gruver    public static boolean assemble(final SmaliOptions options, String... input) throws IOException {
65735746595fc623181546a08f415efd5215d88657Ben Gruver        return assemble(options, Arrays.asList(input));
66735746595fc623181546a08f415efd5215d88657Ben Gruver    }
67735746595fc623181546a08f415efd5215d88657Ben Gruver
68735746595fc623181546a08f415efd5215d88657Ben Gruver    /**
69735746595fc623181546a08f415efd5215d88657Ben Gruver     * Assemble the specified files, using the given options
70735746595fc623181546a08f415efd5215d88657Ben Gruver     *
71735746595fc623181546a08f415efd5215d88657Ben Gruver     * @param options a SmaliOptions object with the options to run smali with
72735746595fc623181546a08f415efd5215d88657Ben Gruver     * @param input The files/directories to process
73735746595fc623181546a08f415efd5215d88657Ben Gruver     * @return true if assembly completed with no errors, or false if errors were encountered
74735746595fc623181546a08f415efd5215d88657Ben Gruver     */
75735746595fc623181546a08f415efd5215d88657Ben Gruver    public static boolean assemble(final SmaliOptions options, List<String> input) throws IOException {
76735746595fc623181546a08f415efd5215d88657Ben Gruver        LinkedHashSet<File> filesToProcessSet = new LinkedHashSet<File>();
77735746595fc623181546a08f415efd5215d88657Ben Gruver
78735746595fc623181546a08f415efd5215d88657Ben Gruver        for (String fileToProcess: input) {
79735746595fc623181546a08f415efd5215d88657Ben Gruver            File argFile = new File(fileToProcess);
80735746595fc623181546a08f415efd5215d88657Ben Gruver
81735746595fc623181546a08f415efd5215d88657Ben Gruver            if (!argFile.exists()) {
82735746595fc623181546a08f415efd5215d88657Ben Gruver                throw new IllegalArgumentException("Cannot find file or directory \"" + fileToProcess + "\"");
83735746595fc623181546a08f415efd5215d88657Ben Gruver            }
84735746595fc623181546a08f415efd5215d88657Ben Gruver
85735746595fc623181546a08f415efd5215d88657Ben Gruver            if (argFile.isDirectory()) {
86735746595fc623181546a08f415efd5215d88657Ben Gruver                getSmaliFilesInDir(argFile, filesToProcessSet);
87735746595fc623181546a08f415efd5215d88657Ben Gruver            } else if (argFile.isFile()) {
88735746595fc623181546a08f415efd5215d88657Ben Gruver                filesToProcessSet.add(argFile);
89735746595fc623181546a08f415efd5215d88657Ben Gruver            }
90735746595fc623181546a08f415efd5215d88657Ben Gruver        }
91735746595fc623181546a08f415efd5215d88657Ben Gruver
92735746595fc623181546a08f415efd5215d88657Ben Gruver        boolean errors = false;
93735746595fc623181546a08f415efd5215d88657Ben Gruver
945189797292086a051666cf8c96cf44c6a23321b6Ben Gruver        final DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(options.apiLevel));
95735746595fc623181546a08f415efd5215d88657Ben Gruver
96735746595fc623181546a08f415efd5215d88657Ben Gruver        ExecutorService executor = Executors.newFixedThreadPool(options.jobs);
97735746595fc623181546a08f415efd5215d88657Ben Gruver        List<Future<Boolean>> tasks = Lists.newArrayList();
98735746595fc623181546a08f415efd5215d88657Ben Gruver
99735746595fc623181546a08f415efd5215d88657Ben Gruver        for (final File file: filesToProcessSet) {
100735746595fc623181546a08f415efd5215d88657Ben Gruver            tasks.add(executor.submit(new Callable<Boolean>() {
101735746595fc623181546a08f415efd5215d88657Ben Gruver                @Override public Boolean call() throws Exception {
102735746595fc623181546a08f415efd5215d88657Ben Gruver                    return assembleSmaliFile(file, dexBuilder, options);
103735746595fc623181546a08f415efd5215d88657Ben Gruver                }
104735746595fc623181546a08f415efd5215d88657Ben Gruver            }));
105735746595fc623181546a08f415efd5215d88657Ben Gruver        }
106735746595fc623181546a08f415efd5215d88657Ben Gruver
107735746595fc623181546a08f415efd5215d88657Ben Gruver        for (Future<Boolean> task: tasks) {
108735746595fc623181546a08f415efd5215d88657Ben Gruver            while(true) {
109735746595fc623181546a08f415efd5215d88657Ben Gruver                try {
110735746595fc623181546a08f415efd5215d88657Ben Gruver                    try {
111735746595fc623181546a08f415efd5215d88657Ben Gruver                        if (!task.get()) {
112735746595fc623181546a08f415efd5215d88657Ben Gruver                            errors = true;
113735746595fc623181546a08f415efd5215d88657Ben Gruver                        }
114735746595fc623181546a08f415efd5215d88657Ben Gruver                    } catch (ExecutionException ex) {
115735746595fc623181546a08f415efd5215d88657Ben Gruver                        throw new RuntimeException(ex);
116735746595fc623181546a08f415efd5215d88657Ben Gruver                    }
117735746595fc623181546a08f415efd5215d88657Ben Gruver                } catch (InterruptedException ex) {
118735746595fc623181546a08f415efd5215d88657Ben Gruver                    continue;
119735746595fc623181546a08f415efd5215d88657Ben Gruver                }
120735746595fc623181546a08f415efd5215d88657Ben Gruver                break;
121735746595fc623181546a08f415efd5215d88657Ben Gruver            }
122735746595fc623181546a08f415efd5215d88657Ben Gruver        }
123735746595fc623181546a08f415efd5215d88657Ben Gruver
124735746595fc623181546a08f415efd5215d88657Ben Gruver        executor.shutdown();
125735746595fc623181546a08f415efd5215d88657Ben Gruver
126735746595fc623181546a08f415efd5215d88657Ben Gruver        if (errors) {
127735746595fc623181546a08f415efd5215d88657Ben Gruver            return false;
128735746595fc623181546a08f415efd5215d88657Ben Gruver        }
129735746595fc623181546a08f415efd5215d88657Ben Gruver
130735746595fc623181546a08f415efd5215d88657Ben Gruver        dexBuilder.writeTo(new FileDataStore(new File(options.outputDexFile)));
131735746595fc623181546a08f415efd5215d88657Ben Gruver
132735746595fc623181546a08f415efd5215d88657Ben Gruver        return true;
133735746595fc623181546a08f415efd5215d88657Ben Gruver    }
134735746595fc623181546a08f415efd5215d88657Ben Gruver
135735746595fc623181546a08f415efd5215d88657Ben Gruver    private static void getSmaliFilesInDir(@Nonnull File dir, @Nonnull Set<File> smaliFiles) {
136735746595fc623181546a08f415efd5215d88657Ben Gruver        File[] files = dir.listFiles();
137735746595fc623181546a08f415efd5215d88657Ben Gruver        if (files != null) {
138735746595fc623181546a08f415efd5215d88657Ben Gruver            for(File file: files) {
139735746595fc623181546a08f415efd5215d88657Ben Gruver                if (file.isDirectory()) {
140735746595fc623181546a08f415efd5215d88657Ben Gruver                    getSmaliFilesInDir(file, smaliFiles);
141735746595fc623181546a08f415efd5215d88657Ben Gruver                } else if (file.getName().endsWith(".smali")) {
142735746595fc623181546a08f415efd5215d88657Ben Gruver                    smaliFiles.add(file);
143735746595fc623181546a08f415efd5215d88657Ben Gruver                }
144735746595fc623181546a08f415efd5215d88657Ben Gruver            }
145735746595fc623181546a08f415efd5215d88657Ben Gruver        }
146735746595fc623181546a08f415efd5215d88657Ben Gruver    }
147735746595fc623181546a08f415efd5215d88657Ben Gruver
148735746595fc623181546a08f415efd5215d88657Ben Gruver    private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, SmaliOptions options)
149735746595fc623181546a08f415efd5215d88657Ben Gruver            throws Exception {
15043669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski        FileInputStream fis = null;
15143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski        try {
15243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            fis = new FileInputStream(smaliFile);
15343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
15443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski
15543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            LexerErrorInterface lexer = new smaliFlexLexer(reader);
15643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            ((smaliFlexLexer)lexer).setSourceFile(smaliFile);
15743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            CommonTokenStream tokens = new CommonTokenStream((TokenSource)lexer);
15843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski
15943669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            if (options.printTokens) {
16043669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                tokens.getTokens();
16143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski
16243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                for (int i=0; i<tokens.size(); i++) {
16343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                    Token token = tokens.get(i);
16443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                    if (token.getChannel() == smaliParser.HIDDEN) {
16543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                        continue;
16643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                    }
167735746595fc623181546a08f415efd5215d88657Ben Gruver
16843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                    System.out.println(smaliParser.tokenNames[token.getType()] + ": " + token.getText());
169735746595fc623181546a08f415efd5215d88657Ben Gruver                }
170735746595fc623181546a08f415efd5215d88657Ben Gruver
17143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                System.out.flush();
172735746595fc623181546a08f415efd5215d88657Ben Gruver            }
173735746595fc623181546a08f415efd5215d88657Ben Gruver
17443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            smaliParser parser = new smaliParser(tokens);
17543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            parser.setVerboseErrors(options.verboseErrors);
17643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            parser.setAllowOdex(options.allowOdexOpcodes);
17743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            parser.setApiLevel(options.apiLevel);
178735746595fc623181546a08f415efd5215d88657Ben Gruver
17943669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            smaliParser.smali_file_return result = parser.smali_file();
180735746595fc623181546a08f415efd5215d88657Ben Gruver
18143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            if (parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) {
18243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                return false;
18343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            }
184735746595fc623181546a08f415efd5215d88657Ben Gruver
18543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            CommonTree t = result.getTree();
186735746595fc623181546a08f415efd5215d88657Ben Gruver
18743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
18843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            treeStream.setTokenStream(tokens);
189735746595fc623181546a08f415efd5215d88657Ben Gruver
19043669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            if (options.printTokens) {
19143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                System.out.println(t.toStringTree());
19243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            }
193735746595fc623181546a08f415efd5215d88657Ben Gruver
19443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
19543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            dexGen.setApiLevel(options.apiLevel);
196735746595fc623181546a08f415efd5215d88657Ben Gruver
19743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            dexGen.setVerboseErrors(options.verboseErrors);
19843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            dexGen.setDexBuilder(dexBuilder);
19943669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            dexGen.smali_file();
200735746595fc623181546a08f415efd5215d88657Ben Gruver
20143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            return dexGen.getNumberOfSyntaxErrors() == 0;
20243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski        } finally {
20343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            if (fis != null) {
20443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski                fis.close();
20543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski            }
20643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski        }
207735746595fc623181546a08f415efd5215d88657Ben Gruver    }
208735746595fc623181546a08f415efd5215d88657Ben Gruver}
209