1/*
2 * Copyright 2014, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.smali;
33
34import com.google.common.collect.Iterables;
35import org.antlr.runtime.CommonTokenStream;
36import org.antlr.runtime.RecognitionException;
37import org.antlr.runtime.TokenSource;
38import org.antlr.runtime.tree.CommonTree;
39import org.antlr.runtime.tree.CommonTreeNodeStream;
40import org.jf.dexlib2.Opcodes;
41import org.jf.dexlib2.dexbacked.DexBackedDexFile;
42import org.jf.dexlib2.iface.ClassDef;
43import org.jf.dexlib2.writer.builder.DexBuilder;
44import org.jf.dexlib2.writer.io.MemoryDataStore;
45
46import java.io.IOException;
47import java.io.Reader;
48import java.io.StringReader;
49
50public class SmaliTestUtils {
51
52    public static ClassDef compileSmali(String smaliText) throws RecognitionException, IOException {
53        return compileSmali(smaliText, 15);
54    }
55
56    public static ClassDef compileSmali(String smaliText, int apiLevel)
57            throws RecognitionException, IOException {
58        CommonTokenStream tokens;
59        LexerErrorInterface lexer;
60        DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(apiLevel));
61
62        Reader reader = new StringReader(smaliText);
63
64        lexer = new smaliFlexLexer(reader);
65        tokens = new CommonTokenStream((TokenSource)lexer);
66
67        smaliParser parser = new smaliParser(tokens);
68        parser.setVerboseErrors(true);
69        parser.setAllowOdex(false);
70        parser.setApiLevel(apiLevel);
71
72        smaliParser.smali_file_return result = parser.smali_file();
73
74        if(parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) {
75            throw new RuntimeException("Error occured while compiling text");
76        }
77
78        CommonTree t = result.getTree();
79
80        CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
81        treeStream.setTokenStream(tokens);
82
83        smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
84        dexGen.setApiLevel(apiLevel);
85        dexGen.setVerboseErrors(true);
86        dexGen.setDexBuilder(dexBuilder);
87        dexGen.smali_file();
88
89        if (dexGen.getNumberOfSyntaxErrors() > 0) {
90            throw new RuntimeException("Error occured while compiling text");
91        }
92
93        MemoryDataStore dataStore = new MemoryDataStore();
94
95        dexBuilder.writeTo(dataStore);
96
97        DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.forApi(apiLevel), dataStore.getData());
98
99        return Iterables.getFirst(dexFile.getClasses(), null);
100    }
101}
102