/* * 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; type += "="; //$NON-NLS-1$ while((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; 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(); } } 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; } }