15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.content.common;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.text.TextUtils;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log;
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.File;
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.FileInputStream;
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.FileNotFoundException;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.IOException;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.InputStreamReader;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.Reader;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.ArrayList;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Arrays;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.HashMap;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.concurrent.atomic.AtomicReference;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Java mirror of Chrome command-line utilities (e.g. class CommandLine from base/command_line.h).
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Command line program adb_command_line can be used to set the Chrome command line:
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * adb shell "echo chrome --my-param > /data/local/chrome-command-line"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public abstract class CommandLine {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Block onCreate() of Chrome until a Java debugger is attached.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tell Java to use the official command line, loaded from the
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // official-command-line.xml files.  WARNING this is not done
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // immediately on startup, so early running Java code will not see
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // these flags.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String ADD_OFFICIAL_COMMAND_LINE = "add-official-command-line";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Enables test intent handling.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String ENABLE_TEST_INTENTS = "enable-test-intents";
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Dump frames-per-second to the log
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String LOG_FPS = "log-fps";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Whether Chromium should use a mobile user agent.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String USE_MOBILE_UA = "use-mobile-user-agent";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // tablet specific UI components.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Native switch - chrome_switches::kTabletUI
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String TABLET_UI = "tablet-ui";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Change the url of the JavaScript that gets injected when accessibility mode is enabled.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String ACCESSIBILITY_JAVASCRIPT_URL = "accessibility-js-url";
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String ACCESSIBILITY_DEBUG_BRAILLE_SERVICE = "debug-braille-service";
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sets the ISO country code that will be used for phone number detection.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String NETWORK_COUNTRY_ISO = "network-country-iso";
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Whether to enable the auto-hiding top controls.
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String ENABLE_TOP_CONTROLS_POSITION_CALCULATION
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            = "enable-top-controls-position-calculation";
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The height of the movable top controls.
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String TOP_CONTROLS_HEIGHT = "top-controls-height";
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // How much of the top controls need to be shown before they will auto show.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String TOP_CONTROLS_SHOW_THRESHOLD = "top-controls-show-threshold";
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // How much of the top controls need to be hidden before they will auto hide.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String TOP_CONTROLS_HIDE_THRESHOLD = "top-controls-hide-threshold";
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Native switch - chrome_switches::kEnableInstantExtendedAPI
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public static final String ENABLE_INSTANT_EXTENDED_API = "enable-instant-extended-api";
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Native switch - content_switches::kEnableSpeechRecognition
74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    public static final String ENABLE_SPEECH_RECOGNITION = "enable-speech-recognition";
75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    // Native switch - shell_switches::kDumpRenderTree
773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    public static final String DUMP_RENDER_TREE = "dump-render-tree";
783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Public abstract interface, implemented in derived classes.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // All these methods reflect their native-side counterparts.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *  Returns true if this command line contains the given switch.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *  (Switch names ARE case-sensitive).
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public abstract boolean hasSwitch(String switchString);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Return the value associated with the given switch, or null.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param switchString The switch key to lookup. It should NOT start with '--' !
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return switch value, or null if the switch is not set or set to empty.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public abstract String getSwitchValue(String switchString);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Return the value associated with the given switch, or {@code defaultValue} if the switch
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * was not specified.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param switchString The switch key to lookup. It should NOT start with '--' !
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param defaultValue The default value to return if the switch isn't set.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return Switch value, or {@code defaultValue} if the switch is not set or set to empty.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public String getSwitchValue(String switchString, String defaultValue) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String value = getSwitchValue(switchString);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return TextUtils.isEmpty(value) ? defaultValue : value;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Append a switch to the command line.  There is no guarantee
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * this action happens before the switch is needed.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param switchString the switch to add.  It should NOT start with '--' !
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public abstract void appendSwitch(String switchString);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Append a switch and value to the command line.  There is no
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * guarantee this action happens before the switch is needed.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param switchString the switch to add.  It should NOT start with '--' !
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param value the value for this switch.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * For example, --foo=bar becomes 'foo', 'bar'.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public abstract void appendSwitchWithValue(String switchString, String value);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Append switch/value items in "command line" format (excluding argv[0] program name).
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * E.g. { '--gofast', '--username=fred' }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param array an array of switch or switch/value items in command line format.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *   Unlike the other append routines, these switches SHOULD start with '--' .
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *   Unlike init(), this does not include the program name in array[0].
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public abstract void appendSwitchesAndArguments(String[] array);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Determine if the command line is bound to the native (JNI) implementation.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return true if the underlying implementation is delegating to the native command line.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public boolean isNativeImplementation() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final AtomicReference<CommandLine> sCommandLine =
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new AtomicReference<CommandLine>();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @returns true if the command line has already been initialized.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static boolean isInitialized() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return sCommandLine.get() != null;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Equivalent to CommandLine::ForCurrentProcess in C++.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static CommandLine getInstance() {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CommandLine commandLine = sCommandLine.get();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert commandLine != null;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return commandLine;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Initialize the singleton instance, must be called exactly once (either directly or
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * via one of the convenience wrappers below) before using the static singleton instance.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param args command line flags in 'argv' format: args[0] is the program name.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static void init(String[] args) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setInstance(new JavaCommandLine(args));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Initialize the command line from the command-line file.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param file The fully qualified command line file.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static void initFromFile(String file) {
171558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        // Arbitrary clamp of 8k on the amount of file we read in.
172558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        char[] buffer = readUtf8FileFully(file, 8 * 1024);
173558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        init(buffer == null ? null : tokenizeQuotedAruments(buffer));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Resets both the java proxy and the native command lines. This allows the entire
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * command line initialization to be re-run including the call to onJniLoaded.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static void reset() {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setInstance(null);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Public for testing (TODO: why are the tests in a different package?)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Parse command line flags from a flat buffer, supporting double-quote enclosed strings
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * containing whitespace. argv elements are derived by splitting the buffer on whitepace;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * double quote characters may enclose tokens containing whitespace; a double-quote literal
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * may be escaped with back-slash. (Otherwise backslash is taken as a literal).
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param buffer A command line in command line file format as described above.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return the tokenized arguments, suitable for passing to init().
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static String[] tokenizeQuotedAruments(char[] buffer) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ArrayList<String> args = new ArrayList<String>();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StringBuilder arg = null;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        final char noQuote = '\0';
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        final char singleQuote = '\'';
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        final char doubleQuote = '"';
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        char currentQuote = noQuote;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (char c : buffer) {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Detect start or end of quote block.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote)) ||
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                c == currentQuote) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    // Last char was a backslash; pop it, and treat c as a literal.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    arg.setCharAt(arg.length() - 1, c);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                } else {
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    currentQuote = currentQuote == noQuote ? c : noQuote;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            } else if (currentQuote == noQuote && Character.isWhitespace(c)) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (arg != null) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    args.add(arg.toString());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    arg = null;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            } else {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (arg == null) arg = new StringBuilder();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                arg.append(c);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (arg != null) {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (currentQuote != noQuote) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                Log.w(TAG, "Unterminated quoted string: " + arg);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add(arg.toString());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return args.toArray(new String[args.size()]);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String TAG = "CommandLine";
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String SWITCH_PREFIX = "--";
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String SWITCH_TERMINATOR = SWITCH_PREFIX;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String SWITCH_VALUE_SEPARATOR = "=";
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static void enableNativeProxy() {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Make a best-effort to ensure we make a clean (atomic) switch over from the old to
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the new command line implementation. If another thread is modifying the command line
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // when this happens, all bets are off. (As per the native CommandLine).
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sCommandLine.set(new NativeCommandLine());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static String[] getJavaSwitchesOrNull() {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CommandLine commandLine = sCommandLine.get();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (commandLine != null) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            assert !commandLine.isNativeImplementation();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return ((JavaCommandLine) commandLine).getCommandLineArguments();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return null;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static void setInstance(CommandLine commandLine) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CommandLine oldCommandLine = sCommandLine.getAndSet(commandLine);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (oldCommandLine != null && oldCommandLine.isNativeImplementation()) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nativeReset();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param fileName the file to read in.
259558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch     * @param sizeLimit cap on the file size.
260558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch     * @return Array of chars read from the file, or null if the file cannot be read
261558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch     *         or if its length exceeds |sizeLimit|.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
263558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    private static char[] readUtf8FileFully(String fileName, int sizeLimit) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Reader reader = null;
265558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        File f = new File(fileName);
266558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        long fileLength = f.length();
267558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
268558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        if (fileLength == 0) {
269558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            return null;
270558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        }
271558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
272558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        if (fileLength > sizeLimit) {
273558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds limit "
274558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                    + sizeLimit);
275558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            return null;
276558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        }
277558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
279558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            char[] buffer = new char[(int) fileLength];
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            int charsRead = reader.read(buffer);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Debug check that we've exhausted the input stream (will fail e.g. if the
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // file grew after we inspected its length).
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            assert !reader.ready();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
286558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        } catch (FileNotFoundException e) {
287558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            return null;
288558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        } catch (IOException e) {
289558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            return null;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } finally {
291558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            try {
292558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                if (reader != null) reader.close();
293558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            } catch (IOException e) {
294558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                Log.e(TAG, "Unable to close file reader.", e);
295558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private CommandLine() {}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static class JavaCommandLine extends CommandLine {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private HashMap<String, String> mSwitches = new HashMap<String, String>();
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private ArrayList<String> mArgs = new ArrayList<String>();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The arguments begin at index 1, since index 0 contains the executable name.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private int mArgsBegin = 1;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        JavaCommandLine(String[] args) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (args == null || args.length == 0 || args[0] == null) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mArgs.add("");
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            } else {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mArgs.add(args[0]);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                appendSwitchesInternal(args, 1);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Invariant: we always have the argv[0] program name element.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            assert mArgs.size() > 0;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Returns the switches and arguments passed into the program, with switches and their
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * values coming before all of the arguments.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private String[] getCommandLineArguments() {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mArgs.toArray(new String[mArgs.size()]);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public boolean hasSwitch(String switchString) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mSwitches.containsKey(switchString);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public String getSwitchValue(String switchString) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // This is slightly round about, but needed for consistency with the NativeCommandLine
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // version which does not distinguish empty values from key not present.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String value = mSwitches.get(switchString);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return value == null || value.isEmpty() ? null : value;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void appendSwitch(String switchString) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            appendSwitchWithValue(switchString, null);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Appends a switch to the current list.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param switchString the switch to add.  It should NOT start with '--' !
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param value the value for this switch.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void appendSwitchWithValue(String switchString, String value) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mSwitches.put(switchString, value == null ? "" : value);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Append the switch and update the switches/arguments divider mArgsBegin.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String combinedSwitchString = SWITCH_PREFIX + switchString;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (value != null && !value.isEmpty())
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                combinedSwitchString += SWITCH_VALUE_SEPARATOR + value;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mArgs.add(mArgsBegin++, combinedSwitchString);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void appendSwitchesAndArguments(String[] array) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            appendSwitchesInternal(array, 0);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Add the specified arguments, but skipping the first |skipCount| elements.
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private void appendSwitchesInternal(String[] array, int skipCount) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            boolean parseSwitches = true;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for (String arg : array) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (skipCount > 0) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    --skipCount;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    continue;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (arg.equals(SWITCH_TERMINATOR)) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    parseSwitches = false;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    String value = parts.length > 1 ? parts[1] : null;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.length()), value);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                } else {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    mArgs.add(arg);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static class NativeCommandLine extends CommandLine {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public boolean hasSwitch(String switchString) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return nativeHasSwitch(switchString);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public String getSwitchValue(String switchString) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return nativeGetSwitchValue(switchString);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void appendSwitch(String switchString) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nativeAppendSwitch(switchString);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void appendSwitchWithValue(String switchString, String value) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nativeAppendSwitchWithValue(switchString, value);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void appendSwitchesAndArguments(String[] array) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nativeAppendSwitchesAndArguments(array);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public boolean isNativeImplementation() {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return true;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static native void nativeReset();
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static native boolean nativeHasSwitch(String switchString);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static native String nativeGetSwitchValue(String switchString);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static native void nativeAppendSwitch(String switchString);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static native void nativeAppendSwitchWithValue(String switchString, String value);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static native void nativeAppendSwitchesAndArguments(String[] array);
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
430