| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package flash.tools.debugger; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.LineNumberReader; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import flash.util.Trace; |
| |
| /** |
| * @author mmorearty |
| */ |
| public class DefaultDebuggerCallbacks implements IDebuggerCallbacks |
| { |
| private boolean m_computedExeLocations; |
| private File m_httpExe; |
| private File m_playerExe; |
| |
| private static final String UNIX_DEFAULT_BROWSER = "firefox"; //$NON-NLS-1$ |
| private static final String UNIX_FLASH_PLAYER = "flashplayer"; //$NON-NLS-1$ |
| |
| private static final int WINDOWS = 0; |
| private static final int MAC = 1; |
| private static final int UNIX = 2; |
| |
| // A pattern for a value that was output by reg.exe. Warning, |
| // Windows XP and Windows Vista have different output; the following |
| // pattern needs to work for both. |
| private static final Pattern registryValuePattern = Pattern.compile("\\sREG_[^ \t]+\\s+(.*)$"); //$NON-NLS-1$ |
| |
| /** |
| * Returns WINDOWS, MAC, or UNIX |
| */ |
| private static int getOS() { |
| String osName = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$ |
| if (osName.startsWith("windows")) //$NON-NLS-1$ |
| return WINDOWS; |
| else if (osName.startsWith("mac os x")) // as per http://developer.apple.com/technotes/tn2002/tn2110.html //$NON-NLS-1$ |
| return MAC; |
| else |
| return UNIX; |
| } |
| |
| /* |
| * @see flash.tools.debugger.IDebuggerCallbacks#getHttpExe() |
| */ |
| public synchronized File getHttpExe() |
| { |
| if (!m_computedExeLocations) |
| recomputeExeLocations(); |
| return m_httpExe; |
| } |
| |
| /* |
| * @see flash.tools.debugger.IDebuggerCallbacks#getPlayerExe() |
| */ |
| public synchronized File getPlayerExe() |
| { |
| if (!m_computedExeLocations) |
| recomputeExeLocations(); |
| return m_playerExe; |
| } |
| |
| /* |
| * @see flash.tools.debugger.IDebuggerCallbacks#recomputeExeLocations() |
| */ |
| public synchronized void recomputeExeLocations() |
| { |
| int os = getOS(); |
| if (os == WINDOWS) |
| { |
| m_httpExe = getDefaultWindowsBrowser(); |
| m_playerExe = determineExeForType("ShockwaveFlash.ShockwaveFlash"); //$NON-NLS-1$ |
| } |
| else if (os == MAC) |
| { |
| m_httpExe = null; |
| m_playerExe = null; |
| } |
| else // probably Unix |
| { |
| // "firefox" is default browser for unix |
| m_httpExe = findUnixProgram(UNIX_DEFAULT_BROWSER); |
| |
| // "flashplayer" is standalone flash player on unix |
| m_playerExe = findUnixProgram(UNIX_FLASH_PLAYER); |
| } |
| m_computedExeLocations = true; |
| } |
| |
| public String getHttpExeName() |
| { |
| if (getOS() == UNIX) |
| return UNIX_DEFAULT_BROWSER; |
| else |
| return Bootstrap.getLocalizationManager().getLocalizedTextString("webBrowserGenericName"); //$NON-NLS-1$ |
| } |
| |
| public String getPlayerExeName() |
| { |
| if (getOS() == UNIX) |
| return UNIX_FLASH_PLAYER; |
| else |
| return Bootstrap.getLocalizationManager().getLocalizedTextString("flashPlayerGenericName"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Looks for a Unix program. Checks the PATH, and if not found there, |
| * checks the directory specified by the "application.home" Java property. |
| * ("application.home" was set by the "fdb" shell script.) |
| * |
| * @param program program to find, e.g. "firefox" |
| * @return path, or <code>null</code> if not found. |
| */ |
| private File findUnixProgram(String program) |
| { |
| String[] cmd = { "/bin/sh", "-c", "which " + program }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| try |
| { |
| Process process = Runtime.getRuntime().exec(cmd); |
| BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); |
| String line = reader.readLine(); |
| if (line != null) |
| { |
| File f = new File(line); |
| if (f.exists()) |
| { |
| return f; |
| } |
| } |
| |
| // Check in the Flex SDK's "bin" directory. The "application.home" |
| // property is set by the "fdb" shell script. |
| String flexHome = System.getProperty("application.home"); //$NON-NLS-1$ |
| if (flexHome != null) |
| { |
| File f = new File(flexHome, "bin/" + program); //$NON-NLS-1$ |
| if (f.exists()) |
| { |
| return f; |
| } |
| } |
| } |
| catch (IOException e) |
| { |
| // ignore |
| } |
| return null; |
| } |
| |
| private File getDefaultWindowsBrowser() { |
| try { |
| String browser = null; |
| |
| double osVersion; |
| try { |
| osVersion = Double.parseDouble(System.getProperty("os.version")); //$NON-NLS-1$ |
| } catch (NumberFormatException e) { |
| osVersion = 0; |
| } |
| |
| if (osVersion >= 6) { // Vista or higher |
| String progid = queryWindowsRegistry( |
| "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice", //$NON-NLS-1$ |
| "Progid"); //$NON-NLS-1$ |
| if (progid != null) { |
| browser = getClassShellOpenCommand(progid); |
| } |
| } |
| |
| if (browser == null) { |
| browser = getClassShellOpenCommand("http"); //$NON-NLS-1$ |
| } |
| |
| if (browser != null) { |
| browser = extractExenameFromCommandString(browser); |
| return new File(browser); |
| } else { |
| return null; |
| } |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| private String getClassShellOpenCommand(String clazz) throws IOException { |
| return queryWindowsRegistry("HKEY_CLASSES_ROOT\\" + clazz + "\\shell\\open\\command", null); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Note, this function is Windows-specific. |
| */ |
| private File determineExeForType(String type) |
| { |
| String it = null; |
| try |
| { |
| String[] cmd = new String[] { "cmd", "/d", "/c", "ftype", type }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| Process p = Runtime.getRuntime().exec(cmd); |
| LineNumberReader lnr = new LineNumberReader(new InputStreamReader(p.getInputStream())); |
| String line = null; |
| type += "="; //$NON-NLS-1$ |
| while( it == null && (line = lnr.readLine()) != null) |
| { |
| if (line.length() < type.length() || |
| line.substring(0, type.length()).compareToIgnoreCase(type) == 0) |
| { |
| it = line; |
| break; |
| } |
| } |
| p.destroy(); |
| |
| // if we have one extract cmd = " " |
| if (it != null) |
| { |
| int equalSign = it.indexOf('='); |
| if (equalSign != -1) |
| it = it.substring(equalSign+1); |
| |
| it = extractExenameFromCommandString(it); |
| } |
| } |
| catch (IOException e) |
| { |
| // means it didn't work |
| } |
| |
| if (it != null) |
| return new File(it); |
| else |
| return null; |
| } |
| |
| /** |
| * Given a command string of the form |
| * "path_to_exe" args |
| * or |
| * path_to_exe args |
| * |
| * return the path_to_exe. Note that path_to_exe may contain spaces. |
| */ |
| protected String extractExenameFromCommandString(String cmd) |
| { |
| // now strip trailing junk if any |
| if (cmd.startsWith("\"")) { //$NON-NLS-1$ |
| // ftype is enclosed in quotes |
| int closingQuote = cmd.indexOf('"', 1); |
| if (closingQuote == -1) |
| closingQuote = cmd.length(); |
| cmd = cmd.substring(1, closingQuote); |
| } else { |
| // Some ftypes don't use enclosing quotes. This is tricky -- we have to |
| // scan through the string, stopping at each space and checking whether |
| // the filename up to that point refers to a valid filename. For example, |
| // if the input string is |
| // |
| // C:\Program Files\Macromedia\Flash 9\Players\SAFlashPlayer.exe %1 |
| // |
| // then we need to stop at each space and see if that is an EXE name: |
| // |
| // C:\Program.exe |
| // C:\Program Files\Macromedia\Flash.exe |
| // C:\Program Files\Macromedia\Flash 9\Players\SAFlashPlayer.exe |
| |
| int endOfFilename = -1; |
| for (;;) { |
| int nextSpace = cmd.indexOf(' ', endOfFilename+1); |
| if (nextSpace == -1) { |
| endOfFilename = -1; |
| break; |
| } |
| String filename = cmd.substring(0, nextSpace); |
| if (!filename.toLowerCase().endsWith(".exe")) //$NON-NLS-1$ |
| filename += ".exe"; //$NON-NLS-1$ |
| if (new File(filename).exists()) { |
| endOfFilename = nextSpace; |
| break; |
| } |
| endOfFilename = nextSpace; |
| } |
| if (endOfFilename != -1 && endOfFilename < cmd.length()) |
| cmd = cmd.substring(0, endOfFilename); |
| } |
| return cmd; |
| } |
| |
| /* |
| * @see flash.tools.debugger.IDebuggerCallbacks#launchDebugTarget(java.lang.String[]) |
| */ |
| public Process launchDebugTarget(String[] cmd) throws IOException |
| { |
| return Runtime.getRuntime().exec(cmd); |
| } |
| |
| @Override |
| public Process launchDebugTarget(String[] cmd, ILauncher launcher) throws IOException { |
| return launcher.launch(cmd); |
| } |
| |
| /* |
| * @see flash.tools.debugger.IDebuggerCallbacks#terminateDebugTarget(java.lang.Process) |
| */ |
| public void terminateDebugTarget(Process process) throws IOException |
| { |
| terminateDebugTarget(process, null); |
| } |
| |
| @Override |
| public void terminateDebugTarget(Process process, ILauncher launcher) throws IOException { |
| if(null == launcher) |
| { |
| process.destroy(); |
| } |
| else |
| { |
| launcher.terminate(process); |
| } |
| |
| } |
| |
| public String queryWindowsRegistry(String key, String value) throws IOException |
| { |
| return queryWindowsRegistry(key, value, 0); |
| } |
| |
| /** |
| * This implementation of queryWindowsRegistry() does not make any native |
| * calls. I had to do it this way because it is too hard, at this point, |
| * to add native code to the Flex code tree. |
| */ |
| public String queryWindowsRegistry(String key, String value, int registryBitMode) throws IOException |
| { |
| Process p = null; |
| String result = null; |
| |
| List<String> arguments = new ArrayList<String>(6); |
| arguments.add("reg.exe"); //$NON-NLS-1$ |
| arguments.add("query"); //$NON-NLS-1$ |
| arguments.add(key); |
| if (value == null || value.length() == 0) |
| { |
| arguments.add("/ve"); //$NON-NLS-1$ |
| } |
| else |
| { |
| arguments.add("/v"); //$NON-NLS-1$ |
| arguments.add(value); |
| } |
| |
| // This line must not be in try/catch -- if it throws an exception, |
| // we want that to propagate out to our caller. |
| p = Runtime.getRuntime().exec(arguments.toArray(new String[arguments.size()])); |
| |
| try |
| { |
| BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); |
| |
| String line; |
| while ((line = reader.readLine()) != null) |
| { |
| if (line.equalsIgnoreCase(key)) |
| { |
| line = reader.readLine(); |
| if (line != null) |
| { |
| Matcher matcher = registryValuePattern.matcher(line); |
| if (matcher.find()) { |
| result = matcher.group(1); |
| } |
| } |
| break; |
| } |
| } |
| } |
| catch (IOException e) |
| { |
| if (Trace.error) |
| e.printStackTrace(); |
| } |
| finally |
| { |
| if (p != null) |
| { |
| p.destroy(); |
| p = null; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Default implementation does not know how to get the version |
| * of an application. |
| */ |
| public int[] getAppVersion(File application) throws IOException { |
| return null; |
| } |
| |
| /** |
| * Default application does not have any extra arguments for the |
| * browser. |
| */ |
| public String[] getBrowserParameters(String uri) |
| { |
| return null; |
| } |
| } |