174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com/*
200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * [The "BSD licence"]
300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke)
400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * All rights reserved.
574c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com *
600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without
700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions
800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * are met:
900fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright
1000fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer.
1100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright
1200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer in the
1300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    documentation and/or other materials provided with the distribution.
1400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products
1500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com *    derived from this software without specific prior written permission.
1674c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com *
1700fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1800fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1900fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2000fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2100fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2400fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2500fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2600fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2774c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com */
2874c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
29b09ba849b9ef031ed7b04c90b706bd5cd3b4c748JesusFreke@JesusFreke.compackage org.jf.smali;
3074c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
314c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruverimport com.google.common.collect.Lists;
326c15046f2b744978bb3b03a0697d7865d132fe6eBen Gruverimport org.antlr.runtime.CommonTokenStream;
336c15046f2b744978bb3b03a0697d7865d132fe6eBen Gruverimport org.antlr.runtime.Token;
346c15046f2b744978bb3b03a0697d7865d132fe6eBen Gruverimport org.antlr.runtime.TokenSource;
352cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.comimport org.antlr.runtime.tree.CommonTree;
362cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.comimport org.antlr.runtime.tree.CommonTreeNodeStream;
376b3647e984d4a2b54bee5f5588c36f70a933613bJesusFreke@JesusFreke.comimport org.apache.commons.cli.*;
3842627b850c8f68a594f105e04b97c512b292b698Ben Gruverimport org.jf.dexlib2.writer.builder.DexBuilder;
3999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruverimport org.jf.dexlib2.writer.io.FileDataStore;
406b3647e984d4a2b54bee5f5588c36f70a933613bJesusFreke@JesusFreke.comimport org.jf.util.ConsoleUtil;
4136c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruverimport org.jf.util.SmaliHelpFormatter;
422cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
43894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruverimport javax.annotation.Nonnull;
44a53706985479f8e0a1019fdbd3731ed6063a1627JesusFreke@JesusFreke.comimport java.io.*;
454c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruverimport java.util.*;
464c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruverimport java.util.concurrent.Callable;
474c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruverimport java.util.concurrent.ExecutorService;
484c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruverimport java.util.concurrent.Executors;
494c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruverimport java.util.concurrent.Future;
502cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
5174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com/**
5274c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com * Main class for smali. It recognizes enough options to be able to dispatch
5374c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com * to the right "actual" main.
5474c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com */
5574c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.compublic class main {
5674c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
57a53706985479f8e0a1019fdbd3731ed6063a1627JesusFreke@JesusFreke.com    public static final String VERSION;
5874c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
596d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com    private final static Options basicOptions;
606d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com    private final static Options debugOptions;
612cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    private final static Options options;
6274c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
632cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    static {
646d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        basicOptions = new Options();
656d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        debugOptions = new Options();
662cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        options = new Options();
672cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        buildOptions();
68a53706985479f8e0a1019fdbd3731ed6063a1627JesusFreke@JesusFreke.com
69a53706985479f8e0a1019fdbd3731ed6063a1627JesusFreke@JesusFreke.com        InputStream templateStream = main.class.getClassLoader().getResourceAsStream("smali.properties");
7049fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver        if (templateStream != null) {
7149fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            Properties properties = new Properties();
7249fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            String version = "(unknown)";
7349fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            try {
7449fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver                properties.load(templateStream);
7549fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver                version = properties.getProperty("application.version");
7649fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            } catch (IOException ex) {
7749fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver                // just eat it
7849fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            }
7949fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            VERSION = version;
8049fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver        } else {
8149fa5f5f4438000c1a174ae88d394069bb46f826Ben Gruver            VERSION = "[unknown version]";
82a53706985479f8e0a1019fdbd3731ed6063a1627JesusFreke@JesusFreke.com        }
832cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    }
842cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
8674c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    /**
8774c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     * This class is uninstantiable.
8874c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     */
8974c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    private main() {
9074c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    }
9174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
9274c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    /**
9374c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     * Run!
9474c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     */
9574c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    public static void main(String[] args) {
967bb622e0b16201d0a50e4bdb1f133cbd6477a19aBen Gruver        Locale locale = new Locale("en", "US");
977bb622e0b16201d0a50e4bdb1f133cbd6477a19aBen Gruver        Locale.setDefault(locale);
987bb622e0b16201d0a50e4bdb1f133cbd6477a19aBen Gruver
992cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        CommandLineParser parser = new PosixParser();
1002cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        CommandLine commandLine;
10174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
10274c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com        try {
1032cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            commandLine = parser.parse(options, args);
1042cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        } catch (ParseException ex) {
1052cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            usage();
1062cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            return;
1072cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        }
1082cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1094c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver        int jobs = -1;
11094e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver        boolean allowOdex = false;
11186df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com        boolean verboseErrors = false;
1125922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com        boolean printTokens = false;
1132cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
11483f77f51aa888998486c0c9ad693047480b060b0Ben Gruver        int apiLevel = 15;
115c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver
1162cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        String outputDexFile = "out.dex";
1172cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1182cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        String[] remainingArgs = commandLine.getArgs();
1192cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1206d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        Option[] options = commandLine.getOptions();
1216d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
1226d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        for (int i=0; i<options.length; i++) {
1236d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com            Option option = options[i];
1246d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com            String opt = option.getOpt();
1256d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
1266d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com            switch (opt.charAt(0)) {
1276d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                case 'v':
1286d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    version();
1296d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    return;
1306d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                case '?':
1316d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    while (++i < options.length) {
1326d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                        if (options[i].getOpt().charAt(0) == '?') {
1336d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                            usage(true);
1346d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                            return;
1356d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                        }
1366d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    }
1376d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    usage(false);
1386d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    return;
1396d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                case 'o':
1406d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    outputDexFile = commandLine.getOptionValue("o");
1416d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    break;
14294e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver                case 'x':
14394e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver                    allowOdex = true;
14494e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver                    break;
145c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                case 'a':
146c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                    apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
147c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                    break;
1484c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                case 'j':
1494c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    jobs = Integer.parseInt(commandLine.getOptionValue("j"));
1504c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    break;
15186df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com                case 'V':
15286df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com                    verboseErrors = true;
15386df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com                    break;
1545922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                case 'T':
1555922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                    printTokens = true;
1565922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                    break;
1576d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                default:
1586d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                    assert false;
1596d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com            }
1602cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        }
1612cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1622cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        if (remainingArgs.length == 0) {
1632cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            usage();
1642cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            return;
1652cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        }
1662cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1672cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        try {
1682cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            LinkedHashSet<File> filesToProcess = new LinkedHashSet<File>();
1692cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1702cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            for (String arg: remainingArgs) {
1712cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                    File argFile = new File(arg);
1722cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1732cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                    if (!argFile.exists()) {
1742cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                        throw new RuntimeException("Cannot find file or directory \"" + arg + "\"");
1752cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                    }
1762cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1772cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                    if (argFile.isDirectory()) {
1782cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                        getSmaliFilesInDir(argFile, filesToProcess);
1792cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                    } else if (argFile.isFile()) {
1802cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                        filesToProcess.add(argFile);
1812cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                    }
1822cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            }
1832cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
1844c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            if (jobs <= 0) {
1854c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                jobs = Runtime.getRuntime().availableProcessors();
1864c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                if (jobs > 6) {
1874c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    jobs = 6;
1884c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                }
1894c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            }
1904c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver
1912cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            boolean errors = false;
1922cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
193df8e4802115fadd6bb67ba405aba2db885abbd55Ben Gruver            final DexBuilder dexBuilder = DexBuilder.makeDexBuilder(apiLevel);
1944c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            ExecutorService executor = Executors.newFixedThreadPool(jobs);
1954c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            List<Future<Boolean>> tasks = Lists.newArrayList();
1964c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver
1974c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            final boolean finalVerboseErrors = verboseErrors;
1984c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            final boolean finalPrintTokens = printTokens;
1994c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            final boolean finalAllowOdex = allowOdex;
2004c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            final int finalApiLevel = apiLevel;
2014c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            for (final File file: filesToProcess) {
2024c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                tasks.add(executor.submit(new Callable<Boolean>() {
2034c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    @Override public Boolean call() throws Exception {
2044c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                        return assembleSmaliFile(file, dexBuilder, finalVerboseErrors, finalPrintTokens,
2054c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                                finalAllowOdex, finalApiLevel);
2064c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    }
2074c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                }));
2084c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            }
20942627b850c8f68a594f105e04b97c512b292b698Ben Gruver
2104c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            for (Future<Boolean> task: tasks) {
2114c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                while(true) {
2124c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    try {
2134c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                        if (!task.get()) {
2144c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                            errors = true;
2154c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                        }
2164c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    } catch (InterruptedException ex) {
2174c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                        continue;
2184c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    }
2194c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                    break;
22074c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com                }
22174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            }
2222cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
2234c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver            executor.shutdown();
2244c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver
2252cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            if (errors) {
2262cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                System.exit(1);
2272cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            }
2282cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
22999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver            dexBuilder.writeTo(new FileDataStore(new File(outputDexFile)));
23074c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com        } catch (RuntimeException ex) {
23174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
23274c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            ex.printStackTrace();
23374c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            System.exit(2);
23474c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com        } catch (Throwable ex) {
23574c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            System.err.println("\nUNEXPECTED TOP-LEVEL ERROR:");
23674c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            ex.printStackTrace();
23774c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com            System.exit(3);
23874c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com        }
2392cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    }
24074c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
241894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruver    private static void getSmaliFilesInDir(@Nonnull File dir, @Nonnull Set<File> smaliFiles) {
242894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruver        File[] files = dir.listFiles();
243894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruver        if (files != null) {
244894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruver            for(File file: files) {
24599b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                if (file.isDirectory()) {
24699b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                    getSmaliFilesInDir(file, smaliFiles);
24799b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                } else if (file.getName().endsWith(".smali")) {
24899b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                    smaliFiles.add(file);
24999b46173c5294d186ccf2e647b86346a22b247c8Ben Gruver                }
2502cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            }
25174c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com        }
25242627b850c8f68a594f105e04b97c512b292b698Ben Gruver    }
253311ee79fab06269ea6d9bd31ec1854a6ad036b23JesusFreke@JesusFreke.com
25442627b850c8f68a594f105e04b97c512b292b698Ben Gruver    private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, boolean verboseErrors,
2559c67b1508e5318cb0bc6bef64bddfde592ddbe8dBen Gruver                                             boolean printTokens, boolean allowOdex, int apiLevel)
2562cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            throws Exception {
2574c872e9a7cc5f389449c35f6aea49c8e4ed632d4JesusFreke@JesusFreke.com        CommonTokenStream tokens;
2584c872e9a7cc5f389449c35f6aea49c8e4ed632d4JesusFreke@JesusFreke.com
25952ff693c8f257a2cc3f5f568e7c7e706802b2074JesusFreke@JesusFreke.com        LexerErrorInterface lexer;
26052ff693c8f257a2cc3f5f568e7c7e706802b2074JesusFreke@JesusFreke.com
26148d5b730272ada20e5b8c0245d297b03dbbf6d02Ben Gruver        FileInputStream fis = new FileInputStream(smaliFile.getAbsolutePath());
26248d5b730272ada20e5b8c0245d297b03dbbf6d02Ben Gruver        InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
2634c872e9a7cc5f389449c35f6aea49c8e4ed632d4JesusFreke@JesusFreke.com
26448d5b730272ada20e5b8c0245d297b03dbbf6d02Ben Gruver        lexer = new smaliFlexLexer(reader);
26548d5b730272ada20e5b8c0245d297b03dbbf6d02Ben Gruver        ((smaliFlexLexer)lexer).setSourceFile(smaliFile);
26648d5b730272ada20e5b8c0245d297b03dbbf6d02Ben Gruver        tokens = new CommonTokenStream((TokenSource)lexer);
2672cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
2685922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com        if (printTokens) {
2695922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com            tokens.getTokens();
2705922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com
2715922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com            for (int i=0; i<tokens.size(); i++) {
2725922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                Token token = tokens.get(i);
27348d5b730272ada20e5b8c0245d297b03dbbf6d02Ben Gruver                if (token.getChannel() == smaliParser.HIDDEN) {
2745922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                    continue;
2755922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                }
2765922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com
2775922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                System.out.println(smaliParser.tokenNames[token.getType()] + ": " + token.getText());
2785922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com            }
2795922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com        }
2805922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com
2812cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        smaliParser parser = new smaliParser(tokens);
28286df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com        parser.setVerboseErrors(verboseErrors);
28394e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver        parser.setAllowOdex(allowOdex);
2849c67b1508e5318cb0bc6bef64bddfde592ddbe8dBen Gruver        parser.setApiLevel(apiLevel);
2852cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
2862cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        smaliParser.smali_file_return result = parser.smali_file();
2872cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
28852ff693c8f257a2cc3f5f568e7c7e706802b2074JesusFreke@JesusFreke.com        if (parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) {
2892cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com            return false;
2902cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        }
2912cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
292894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruver        CommonTree t = result.getTree();
2932cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
2942cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
2952cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        treeStream.setTokenStream(tokens);
2962cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
2972cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
298d317a0679d983819f91994b19828e4072918ac4cBen Gruver        dexGen.setVerboseErrors(verboseErrors);
29942627b850c8f68a594f105e04b97c512b292b698Ben Gruver        dexGen.setDexBuilder(dexBuilder);
30042627b850c8f68a594f105e04b97c512b292b698Ben Gruver        dexGen.smali_file();
3012cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
302894327c7ed6c4ffc3a7b9fe61849a878b9a1e8cdBen Gruver        return dexGen.getNumberOfSyntaxErrors() == 0;
30374c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    }
30474c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
3052cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
30674c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    /**
30774c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     * Prints the usage message.
30874c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     */
3096d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com    private static void usage(boolean printDebugOptions) {
31036c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver        SmaliHelpFormatter formatter = new SmaliHelpFormatter();
3116d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
31236c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver        int consoleWidth = ConsoleUtil.getConsoleWidth();
31336c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver        if (consoleWidth <= 0) {
31436c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver            consoleWidth = 80;
31536c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver        }
3166d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
31736c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver        formatter.setWidth(consoleWidth);
3186d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
31936c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver        formatter.printHelp("java -jar smali.jar [options] [--] [<smali-file>|folder]*",
32036c2f08ba064bce2a447f9280bcf80177cb4b9b9Ben Gruver                "assembles a set of smali files into a dex file", basicOptions, printDebugOptions?debugOptions:null);
3216d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com    }
3226d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
3236d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com    private static void usage() {
3246d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        usage(false);
32574c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    }
32674c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com
32774c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    /**
3282cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com     * Prints the version message.
32974c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com     */
3302cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    private static void version() {
3312cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        System.out.println("smali " + VERSION + " (http://smali.googlecode.com)");
33200fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com        System.out.println("Copyright (C) 2010 Ben Gruver (JesusFreke@JesusFreke.com)");
3332cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)");
3342cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        System.exit(0);
3352cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    }
3362cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
337dd77ba20f44e0c40a603a28bd0a9bcb0b6f43dfcBen Gruver    @SuppressWarnings("AccessStaticViaInstance")
3382cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com    private static void buildOptions() {
3392cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        Option versionOption = OptionBuilder.withLongOpt("version")
3402cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                .withDescription("prints the version then exits")
3412cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                .create("v");
3422cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
3432cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        Option helpOption = OptionBuilder.withLongOpt("help")
3446d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com                .withDescription("prints the help message then exits. Specify twice for debug options")
3452cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                .create("?");
3462cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
3472cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com        Option outputOption = OptionBuilder.withLongOpt("output")
348613d7e6f69d2e1e6cdcb448795eb3e35b8014836JesusFreke@JesusFreke.com                .withDescription("the name of the dex file that will be written. The default is out.dex")
3492cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                .hasArg()
3502cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                .withArgName("FILE")
3512cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com                .create("o");
3522cd924697658c4f5196365bc9efe98243b7e279dJesusFreke@JesusFreke.com
35394e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver        Option allowOdexOption = OptionBuilder.withLongOpt("allow-odex-instructions")
3544ba8cebf012c7b3f67d99be22283141d4cdd2216Ben Gruver                .withDescription("allow odex instructions to be compiled into the dex file. Only a few" +
3554ba8cebf012c7b3f67d99be22283141d4cdd2216Ben Gruver                        " instructions are supported - the ones that can exist in a dead code path and not" +
3564ba8cebf012c7b3f67d99be22283141d4cdd2216Ben Gruver                        " cause dalvik to reject the class")
35794e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver                .create("x");
35894e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver
359c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver        Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
360c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                .withDescription("The numeric api-level of the file to generate, e.g. 14 for ICS. If not " +
36183f77f51aa888998486c0c9ad693047480b060b0Ben Gruver                        "specified, it defaults to 15 (ICS).")
362c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                .hasArg()
363c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                .withArgName("API_LEVEL")
364c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver                .create("a");
365c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver
3664c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver        Option jobsOption = OptionBuilder.withLongOpt("jobs")
3674c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                .withDescription("The number of threads to use. Defaults to the number of cores available, up to a " +
3684c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                        "maximum of 6")
3694c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                .hasArg()
3704c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                .withArgName("NUM_THREADS")
3714c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver                .create("j");
3724c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver
37386df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com        Option verboseErrorsOption = OptionBuilder.withLongOpt("verbose-errors")
37486df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com                .withDescription("Generate verbose error messages")
37586df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com                .create("V");
37686df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com
3775922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com        Option printTokensOption = OptionBuilder.withLongOpt("print-tokens")
3785922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                .withDescription("Print the name and text of each token")
3795922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com                .create("T");
3804c872e9a7cc5f389449c35f6aea49c8e4ed632d4JesusFreke@JesusFreke.com
3816d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        basicOptions.addOption(versionOption);
3826d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        basicOptions.addOption(helpOption);
3836d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        basicOptions.addOption(outputOption);
38494e5a39ad28f997442131a5aa3f574dfa80890a0Ben Gruver        basicOptions.addOption(allowOdexOption);
385c2f08d5123c7cdbba3f449b07c46742ab3d7cacbBen Gruver        basicOptions.addOption(apiLevelOption);
3864c431a7ce774616dadb6ff14c064a954f4a1ef6fBen Gruver        basicOptions.addOption(jobsOption);
3876d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
38886df593d85576290a631907f19fcab2656467bdfJesusFreke@JesusFreke.com        debugOptions.addOption(verboseErrorsOption);
3895922b466bf349c4214b5348ee706127a19e440feJesusFreke@JesusFreke.com        debugOptions.addOption(printTokensOption);
3906d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
3916d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        for (Object option: basicOptions.getOptions()) {
3926d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com            options.addOption((Option)option);
3936d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        }
3946d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com
3956d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        for (Object option: debugOptions.getOptions()) {
3966d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com            options.addOption((Option)option);
3976d8f7768380b6d08a255d0893e28c6019d9ff7ccJesusFreke@JesusFreke.com        }
39874c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com    }
39974c7bd560087b4a929bda47592fbb8dcc4ba84f6JesusFreke@JesusFreke.com}