package com.limegroup.gnutella.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; /** * This class handles common utility functions that many classes * may want to access. */ //2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678| public final class CommonUtils { /** * Constant for the current version of LimeWire. */ private static final String LIMEWIRE_VERSION = "@version@"; /** * Variable used for testing only, it's value is set to whatever the test * needs, and getVersion method retuns this value if it's not null */ private static String testVersion = null; /** * The cached value of the major revision number. */ private static final int _majorVersionNumber = getMajorVersionNumberInternal(LIMEWIRE_VERSION); /** * The cached value of the minor revision number. */ private static final int _minorVersionNumber = getMinorVersionNumberInternal(LIMEWIRE_VERSION); /** * The cached value of the really minor version number. */ private static final int _serviceVersionNumber = getServiceVersionNumberInternal(LIMEWIRE_VERSION); /** * The cached value of the GUESS major revision number. */ private static final int _guessMajorVersionNumber = 0; /** * The cached value of the GUESS minor revision number. */ private static final int _guessMinorVersionNumber = 1; /** * The cached value of the Ultrapeer major revision number. */ private static final int _upMajorVersionNumber = 0; /** * The cached value of the Ultrapeer minor revision number. */ private static final int _upMinorVersionNumber = 1; /** * The vendor code for QHD and GWebCache. WARNING: to avoid character * encoding problems, this is hard-coded in QueryReply as well. So if you * change this, you must change QueryReply. */ public static final String QHD_VENDOR_NAME = "LIME"; /** * Constant for the java system properties. */ private static final Properties PROPS = System.getProperties(); /** * Variable for whether or not we're on Windows. */ private static boolean _isWindows = false; /** * Variable for whether or not we're on Windows NT. */ private static boolean _isWindowsNT = false; /** * Variable for whether or not we're on Windows XP. */ private static boolean _isWindowsXP = false; /** * Variable for whether or not we're on Windows NT, 2000, or XP. */ private static boolean _isWindowsNTor2000orXP = false; /** * Variable for whether or not we're on 2000 or XP. */ private static boolean _isWindows2000orXP = false; /** * Variable for whether or not we're on Windows 95. */ private static boolean _isWindows95 = false; /** * Variable for whether or not we're on Windows 98. */ private static boolean _isWindows98 = false; /** * Variable for whether or not we're on Windows Me. */ private static boolean _isWindowsMe = false; /** * Variable for whether or not the operating system allows the * application to be reduced to the system tray. */ private static boolean _supportsTray = false; /** * Variable for whether or not we're on MacOSX. */ private static boolean _isMacOSX = false; /** * Variable for whether or not we're on Linux. */ private static boolean _isLinux = false; /** * Variable for whether or not we're on Solaris. */ private static boolean _isSolaris = false; /** * Variable for whether or not we're on OS/2. */ private static boolean _isOS2 = false; /** * Several arrays of illegal characters on various operating systems. * Used by convertFileName */ private static final char[] ILLEGAL_CHARS_ANY_OS = { '/', '\n', '\r', '\t', '\0', '\f' }; private static final char[] ILLEGAL_CHARS_UNIX = {'`'}; private static final char[] ILLEGAL_CHARS_WINDOWS = { '?', '*', '\\', '<', '>', '|', '\"', ':' }; private static final char[] ILLEGAL_CHARS_MACOS = {':'}; /** * Cached constant for the HTTP Server: header value. */ private static final String HTTP_SERVER; private static final String LIMEWIRE_PREFS_DIR_NAME = ".limewire"; /** * Constant for the current running directory. */ private static final File CURRENT_DIRECTORY = new File(PROPS.getProperty("user.dir")); /** * Variable for whether or not this is a PRO version of LimeWire. */ private static boolean _isPro = false; /** * Variable for the settings directory. */ static File SETTINGS_DIRECTORY = null; /** * Make sure the constructor can never be called. */ private CommonUtils() {} /** * Initialize the settings statically. */ static { setOperatingSystems(); if(!LIMEWIRE_VERSION.endsWith("Pro")) { HTTP_SERVER = "LimeWire/" + LIMEWIRE_VERSION; } else { HTTP_SERVER = ("LimeWire/"+LIMEWIRE_VERSION. substring(0, LIMEWIRE_VERSION.length()-4)+" (Pro)"); _isPro = true; } } /** * Sets the operating system variables. */ private static void setOperatingSystems() { _isWindows = false; _isWindowsNTor2000orXP = false; _isWindows2000orXP = false; _isWindowsNT = false; _isWindowsXP = false; _isWindows95 = false; _isWindows98 = false; _isWindowsMe = false; _isSolaris = false; _isLinux = false; _isOS2 = false; _isMacOSX = false; String os = System.getProperty("os.name").toLowerCase(Locale.US); // set the operating system variables _isWindows = os.indexOf("windows") != -1; if (os.indexOf("windows nt") != -1 || os.indexOf("windows 2000")!= -1 || os.indexOf("windows xp")!= -1) _isWindowsNTor2000orXP = true; if (os.indexOf("windows 2000")!= -1 || os.indexOf("windows xp")!= -1) _isWindows2000orXP = true; if (os.indexOf("windows nt") != -1) _isWindowsNT = true; if (os.indexOf("windows xp") != -1) _isWindowsXP = true; if(os.indexOf("windows 95") != -1) _isWindows95 = true; if(os.indexOf("windows 98") != -1) _isWindows98 = true; if(os.indexOf("windows me") != -1) _isWindowsMe = true; _isSolaris = os.indexOf("solaris") != -1; _isLinux = os.indexOf("linux") != -1; _isOS2 = os.indexOf("os/2") != -1; if(_isWindows || _isLinux) _supportsTray=true; if(os.startsWith("mac os")) { if(os.endsWith("x")) { _isMacOSX = true; } } } /** Gets the major version of GUESS supported. */ public static int getGUESSMajorVersionNumber() { return _guessMajorVersionNumber; } /** Gets the minor version of GUESS supported. */ public static int getGUESSMinorVersionNumber() { return _guessMinorVersionNumber; } /** Gets the major version of Ultrapeer Protocol supported. */ public static int getUPMajorVersionNumber() { return _upMajorVersionNumber; } /** Gets the minor version of Ultrapeer Protocol supported. */ public static int getUPMinorVersionNumber() { return _upMinorVersionNumber; } /** * Returns the current version number of LimeWire as * a string, e.g., "1.4". */ public static String getLimeWireVersion() { if(testVersion==null)//Always the case, except when update tests are run return LIMEWIRE_VERSION; return testVersion; } /** Gets the major version of LimeWire. */ public static int getMajorVersionNumber() { return _majorVersionNumber; } /** Gets the minor version of LimeWire. */ public static int getMinorVersionNumber() { return _minorVersionNumber; } /** Gets the minor minor version of LimeWire. */ public static int getServiceVersionNumber() { return _serviceVersionNumber; } static int getMajorVersionNumberInternal(String version) { if (!version.equals("@" + "version" + "@")) { try { int firstDot = version.indexOf("."); String majorStr = version.substring(0, firstDot); return new Integer(majorStr).intValue(); } catch (NumberFormatException nfe) { } } // in case this is a mainline version or NFE was caught (strange) return 2; } /** * Accessor for whether or not this is LimeWire pro. * * @return <tt>true</tt> if it is pro, otherwise <tt>false</tt> */ public static boolean isPro() { return _isPro; } /** * Accessor for whether or not this is a testing version * (@version@) of LimeWire. * * @return <tt>true</tt> if the version is @version@, * otherwise <tt>false</tt> */ public static boolean isTestingVersion() { return LIMEWIRE_VERSION.equals("@" + "version" + "@"); } static int getMinorVersionNumberInternal(String version) { if (!version.equals("@" + "version" + "@")) { try { int firstDot = version.indexOf("."); String minusMajor = version.substring(firstDot+1); int secondDot = minusMajor.indexOf("."); String minorStr = minusMajor.substring(0, secondDot); return new Integer(minorStr).intValue(); } catch (NumberFormatException nfe) { } } // in case this is a mainline version or NFE was caught (strange) return 7; } static int getServiceVersionNumberInternal(String version) { if (!version.equals("@" + "version" + "@")) { try { int firstDot = version.indexOf("."); int secondDot = version.indexOf(".", firstDot+1); int p = secondDot+1; int q = p; while(q < version.length() && Character.isDigit(version.charAt(q))) { q++; } if (p != q) { String service = version.substring(p, q); return new Integer(service).intValue(); } } catch (NumberFormatException nfe) { } } // in case this is a mainline version or NFE was caught (strange) return 0; } /** * Returns a version number appropriate for upload headers. * Same as '"LimeWire "+getLimeWireVersion'. */ public static String getVendor() { return "LimeWire " + LIMEWIRE_VERSION; } /** * Returns the string for the server that should be reported in the HTTP * "Server: " tag. * * @return the HTTP "Server: " header value */ public static String getHttpServer() { return HTTP_SERVER; } /** * Returns the version of java we're using. */ public static String getJavaVersion() { return PROPS.getProperty("java.version"); } /** * Returns the operating system. */ public static String getOS() { return PROPS.getProperty("os.name"); } /** * Returns the operating system version. */ public static String getOSVersion() { return PROPS.getProperty("os.version"); } /** * Returns the user's current working directory as a <tt>File</tt> * instance, or <tt>null</tt> if the property is not set. * * @return the user's current working directory as a <tt>File</tt> * instance, or <tt>null</tt> if the property is not set */ public static File getCurrentDirectory() { return CURRENT_DIRECTORY; } /** * Returns true if this is Windows NT or Windows 2000 and * hence can support a system tray feature. */ public static boolean supportsTray() { return _supportsTray; } /** * Returns whether or not this operating system is considered * capable of meeting the requirements of a ultrapeer. * * @return <tt>true</tt> if this OS meets ultrapeer requirements, * <tt>false</tt> otherwise */ public static boolean isUltrapeerOS() { return !(_isWindows98 || _isWindows95 || _isWindowsMe || _isWindowsNT); } /** * Returns whether or not the OS is some version of Windows. * * @return <tt>true</tt> if the application is running on some Windows * version, <tt>false</tt> otherwise */ public static boolean isWindows() { return _isWindows; } /** * Returns whether or not the OS is Windows NT, 2000, or XP. * * @return <tt>true</tt> if the application is running on Windows NT, * 2000, or XP <tt>false</tt> otherwise */ public static boolean isWindowsNTor2000orXP() { return _isWindowsNTor2000orXP; } /** * Returns whether or not the OS is 2000 or XP. * * @return <tt>true</tt> if the application is running on 2000 or XP, * <tt>false</tt> otherwise */ public static boolean isWindows2000orXP() { return _isWindows2000orXP; } /** * Returns whether or not the OS is WinXP. * * @return <tt>true</tt> if the application is running on WinXP, * <tt>false</tt> otherwise */ public static boolean isWindowsXP() { return _isWindowsXP; } /** * Returns whether or not the OS is OS/2. * * @return <tt>true</tt> if the application is running on OS/2, * <tt>false</tt> otherwise */ public static boolean isOS2() { return _isOS2; } /** * Returns whether or not the OS is Mac OSX. * * @return <tt>true</tt> if the application is running on Mac OSX, * <tt>false</tt> otherwise */ public static boolean isMacOSX() { return _isMacOSX; } /** * Returns whether or not the OS is Mac OSX 10.2 or above. * * @return <tt>true</tt> if the application is running on Mac OSX, * 10.2 or above, <tt>false</tt> otherwise */ public static boolean isJaguarOrAbove() { if(!isMacOSX()) return false; return getOSVersion().startsWith("10.2"); } /** * Returns whether or not the OS is Mac OSX 10.3 or above. * * @return <tt>true</tt> if the application is running on Mac OSX, * 10.3 or above, <tt>false</tt> otherwise */ public static boolean isPantherOrAbove() { if(!isMacOSX()) return false; return getOSVersion().startsWith("10.3"); } /** * Returns whether or not the Cocoa Foundation classes are available. */ public static boolean isCocoaFoundationAvailable() { if(!isMacOSX()) return false; try { Class.forName("com.apple.cocoa.foundation.NSUserDefaults"); Class.forName("com.apple.cocoa.foundation.NSMutableDictionary"); Class.forName("com.apple.cocoa.foundation.NSMutableArray"); Class.forName("com.apple.cocoa.foundation.NSObject"); Class.forName("com.apple.cocoa.foundation.NSSystem"); return true; } catch(ClassNotFoundException error) { return false; } catch(NoClassDefFoundError error) { return false; } } /** * Returns wheather or not the Log4J library is available */ public static boolean isLog4JAvailable() { try { Class.forName("org.apache.log4j.LogManager"); return true; } catch (ClassNotFoundException ignore) { return false; } catch (NoClassDefFoundError ignore) { return false; } } /** * Returns whether or not the OS is any Mac OS. * * @return <tt>true</tt> if the application is running on Mac OSX * or any previous mac version, <tt>false</tt> otherwise */ public static boolean isAnyMac() { return _isMacOSX; } /** * Returns whether or not the OS is Solaris. * * @return <tt>true</tt> if the application is running on Solaris, * <tt>false</tt> otherwise */ public static boolean isSolaris() { return _isSolaris; } /** * Returns whether or not the OS is Linux. * * @return <tt>true</tt> if the application is running on Linux, * <tt>false</tt> otherwise */ public static boolean isLinux() { return _isLinux; } /** * Returns whether or not the OS is some version of * Unix, defined here as only Solaris or Linux. */ public static boolean isUnix() { return _isLinux || _isSolaris; } /** * Returns whether the OS is POSIX-like. */ public static boolean isPOSIX() { return _isLinux || _isSolaris || _isMacOSX; } /** * Returns whether or not the current JVM is 1.4.x or later * * @return <tt>true</tt> if we are running on 1.4.x or later, * <tt>false</tt> otherwise */ public static boolean isJava14OrLater() { String version=CommonUtils.getJavaVersion(); return !version.startsWith("1.3") && !version.startsWith("1.2") && !version.startsWith("1.1") && !version.startsWith("1.0"); } /** * Returns whether or not the current JVM is 1.4.x or later * * @return <tt>true</tt> if we are running on 1.4.x or later, * <tt>false</tt> otherwise */ public static boolean isJava142OrLater() { String version = CommonUtils.getJavaVersion(); return !version.startsWith("1.4.1") && !version.startsWith("1.4.0") && isJava14OrLater(); } /** * Returns whether or not the current JVM is 1.5.x or later. */ public static boolean isJava15OrLater() { String version=CommonUtils.getJavaVersion(); return !version.startsWith("1.4") && !version.startsWith("1.3") && !version.startsWith("1.2") && !version.startsWith("1.1") && !version.startsWith("1.0"); } /** * Determines if your version of java is out of date. */ public static boolean isJavaOutOfDate() { return isWindows() && !isSpecificJRE() && (getJavaVersion().startsWith("1.3") || getJavaVersion().startsWith("1.4.0")); } /** * Determines if this was loaded from a specific JRE. */ public static boolean isSpecificJRE() { return new File(".", "jre").isDirectory(); } /** * Attempts to copy the first 'amount' bytes of file 'src' to 'dst', * returning the number of bytes actually copied. If 'dst' already exists, * the copy may or may not succeed. * * @param src the source file to copy * @param amount the amount of src to copy, in bytes * @param dst the place to copy the file * @return the number of bytes actually copied. Returns 'amount' if the * entire requested range was copied. */ public static int copy(File src, int amount, File dst) { final int BUFFER_SIZE=1024; int amountToRead=amount; InputStream in=null; OutputStream out=null; try { //I'm not sure whether buffering is needed here. It can't hurt. in=new BufferedInputStream(new FileInputStream(src)); out=new BufferedOutputStream(new FileOutputStream(dst)); byte[] buf=new byte[BUFFER_SIZE]; while (amountToRead>0) { int read=in.read(buf, 0, Math.min(BUFFER_SIZE, amountToRead)); if (read==-1) break; amountToRead-=read; out.write(buf, 0, read); } } catch (IOException e) { } finally { if (in!=null) try { in.close(); } catch (IOException e) { } if (out!=null) { try { out.flush(); } catch (IOException e) { } try { out.close(); } catch (IOException e) { } } } return amount-amountToRead; } /** * Copies the file 'src' to 'dst', returning true iff the copy succeeded. * If 'dst' already exists, the copy may or may not succeed. May also * fail for VERY large source files. */ public static boolean copy(File src, File dst) { //Downcasting length can result in a sign change, causing //copy(File,int,File) to terminate immediately. long length=src.length(); return copy(src, (int)length, dst)==length; } /** * Returns the user home directory. * * @return the <tt>File</tt> instance denoting the abstract pathname of * the user's home directory, or <tt>null</tt> if the home directory * does not exist */ public static File getUserHomeDir() { return new File(PROPS.getProperty("user.home")); } /** * Return the user's name. * * @return the <tt>String</tt> denoting the user's name. */ public static String getUserName() { return PROPS.getProperty("user.name"); } private static synchronized void setUserSettingsDir(File settingsDir) throws IOException, SecurityException { settingsDir = settingsDir.getAbsoluteFile(); if(!settingsDir.isDirectory()) { settingsDir.delete(); // delete whatever it may have been if(!settingsDir.mkdirs()) { String msg = "could not create preferences directory: "+ settingsDir; throw new IOException(msg); } } if(!settingsDir.canWrite()) { throw new IOException("settings dir not writable"); } if(!settingsDir.canRead()) { throw new IOException("settings dir not readable"); } // make sure Windows files are moved moveWindowsFiles(settingsDir); // make sure old metadata files are moved moveXMLFiles(settingsDir); // cache the directory. SETTINGS_DIRECTORY = settingsDir; } /** * Returns the directory where all user settings should be stored. This * is where all application data should be stored. If the directory does * does not already exist, this attempts to create the directory, although * this is not guaranteed to succeed. * * @return the <tt>File</tt> instance denoting the user's home * directory for the application, or <tt>null</tt> if that directory * does not exist */ public synchronized static File getUserSettingsDir() { if ( SETTINGS_DIRECTORY != null ) return SETTINGS_DIRECTORY; File settingsDir = new File(getUserHomeDir(), LIMEWIRE_PREFS_DIR_NAME); if (isWindows()) { String appdata = null; // In some Java 1.4 implementations, System.getenv() is // depricated with prejudice (throws java.lang.Error). if (isJava15OrLater()) { appdata = System.getProperty("LIMEWIRE_PREFS_DIR", System.getenv("APPDATA")); } else { // null string will fall back on default appdata = System.getProperty("LIMEWIRE_PREFS_DIR",null); } if ("%APPDATA%".equals(appdata)) { appdata = null; // fall back on default } if (appdata != null && appdata.length() > 0) { File tempSettingsDir = new File(appdata, "LimeWire"); if (tempSettingsDir.isDirectory() || ! settingsDir.exists()) { try { setUserSettingsDir(tempSettingsDir); return tempSettingsDir; } catch (IOException e) {} // Ignore errors and fall back on default catch (SecurityException e) {} // Ignore errors and fall back on default } } } else if(isMacOSX()) { settingsDir = new File(getUserHomeDir(), "Library/Preferences/LimeWire"); } // Default behavior try { setUserSettingsDir(settingsDir); } catch (IOException e) { throw new RuntimeException(e); } return settingsDir; } /** * Boolean for whether or not the windows files have been copied. */ private static boolean _windowsFilesMoved = false; /** * Boolean for whether or not XML files have been copied. */ private static boolean _xmlFilesMoved = false; /** * The array of files that should be stored in the user's home * directory. */ private static final String[] USER_FILES = { "limewire.props", "gnutella.net", "fileurns.cache" }; /** * On Windows, this copies files from the current directory to the * user's LimeWire home directory. The installer does not have * access to the user's home directory, so these files must be * copied. Note that they are only copied, however, if existing * files are not there. This ensures that the most recent files, * and the files that should be used, should always be saved in * the user's home LimeWire preferences directory. */ private synchronized static void moveWindowsFiles(File settingsDir) { if(!isWindows()) return; if(_windowsFilesMoved) return; File currentDir = CommonUtils.getCurrentDirectory(); for(int i=0; i<USER_FILES.length; i++) { File curUserFile = new File(settingsDir, USER_FILES[i]); File curDirFile = new File(currentDir, USER_FILES[i]); // if the file already exists in the user's home directory, // don't copy it if(curUserFile.isFile()) { continue; } if(!copy(curDirFile, curUserFile)) { throw new RuntimeException(); } } _windowsFilesMoved = true; } /** * Old metadata definitions must be moved from ./lib/xml/data/*.* * This is done like the windows files copying, but for all files * in the data directory. */ private synchronized static void moveXMLFiles(File settingsDir) { if(_xmlFilesMoved) return; // We must extend the currentDir & settingsDir to look // in the right places (lib/xml/data & xml/data). File currentDir = new File( CommonUtils.getCurrentDirectory().getPath() + "/lib/xml/data" ); settingsDir = new File(settingsDir.getPath() + "/xml/data"); settingsDir.mkdirs(); String[] filesToMove = currentDir.list(); if ( filesToMove != null ) { for(int i=0; i<filesToMove.length; i++) { File curUserFile = new File(settingsDir, filesToMove[i]); File curDirFile = new File(currentDir, filesToMove[i]); // if the file already exists in the user's home directory, // don't copy it if(curUserFile.isFile()) { continue; } copy(curDirFile, curUserFile); } } _xmlFilesMoved = true; } /** * Gets a resource file using the CommonUtils class loader, * or the system class loader if CommonUtils isn't loaded. */ public static File getResourceFile(String location) { ClassLoader cl = CommonUtils.class.getClassLoader(); URL resource = null; if(cl == null) { resource = ClassLoader.getSystemResource(location); } else { resource = cl.getResource(location); } if( resource == null ) { // note: this will probably not work, // but it will ultimately trigger a better exception // than returning null. return new File(location); } //NOTE: The resource URL will contain %20 instead of spaces. // This is by design, but will not work when trying to make a file. // See BugParadeID: 4466485 //(http://developer.java.sun.com/developer/bugParade/bugs/4466485.html) // The recommended workaround is to use the URI class, but that doesn't // exist until Java 1.4. So, we can't use it here. // Thus, we manually have to parse out the %20s from the URL return new File( decode(resource.getFile()) ); } /** * Gets an InputStream from a resource file. * * @param location the location of the resource in the resource file * @return an <tt>InputStream</tt> for the resource * @throws IOException if the resource could not be located or there was * another IO error accessing the resource */ public static InputStream getResourceStream(String location) throws IOException { ClassLoader cl = CommonUtils.class.getClassLoader(); URL resource = null; if(cl == null) { resource = ClassLoader.getSystemResource(location); } else { resource = cl.getResource(location); } if( resource == null) throw new IOException("null resource: "+location); else return resource.openStream(); } /** * Copied from URLDecoder.java */ public static String decode(String s) { StringBuffer sb = new StringBuffer(); for(int i=0; i<s.length(); i++) { char c = s.charAt(i); switch (c) { case '+': sb.append(' '); break; case '%': try { sb.append((char)Integer.parseInt( s.substring(i+1,i+3),16)); } catch (NumberFormatException e) { throw new IllegalArgumentException(s); } i += 2; break; default: sb.append(c); break; } } // Undo conversion to external encoding String result = sb.toString(); try { byte[] inputBytes = result.getBytes("8859_1"); result = new String(inputBytes); } catch (UnsupportedEncodingException e) { // The system should always have 8859_1 } return result; } /** * Copies the specified resource file into the current directory from * the jar file. If the file already exists, no copy is performed. * * @param fileName the name of the file to copy, relative to the jar * file -- such as "com/limegroup/gnutella/gui/images/image.gif" */ public static void copyResourceFile(final String fileName) { copyResourceFile(fileName, null); } /** * Copies the specified resource file into the current directory from * the jar file. If the file already exists, no copy is performed. * * @param fileName the name of the file to copy, relative to the jar * file -- such as "com/limegroup/gnutella/gui/images/image.gif" * @param newFile the new <tt>File</tt> instance where the resource file * will be copied to */ public static void copyResourceFile(final String fileName, File newFile) { copyResourceFile(fileName, newFile, false); } /** * Copies the specified resource file into the current directory from * the jar file. If the file already exists, no copy is performed. * * @param fileName the name of the file to copy, relative to the jar * file -- such as "com/limegroup/gnutella/gui/images/image.gif" * @param newFile the new <tt>File</tt> instance where the resource file * will be copied to -- if this argument is null, the file will be * copied to the current directory * @param forceOverwrite specifies whether or not to overwrite the * file if it already exists */ public static void copyResourceFile(final String fileName, File newFile, final boolean forceOverwrite) { if(newFile == null) newFile = new File(".", fileName); // return quickly if the file is already there, no copy necessary if( !forceOverwrite && newFile.exists() ) return; String parentString = newFile.getParent(); if(parentString == null) { return; } File parentFile = new File(parentString); if(!parentFile.isDirectory()) { parentFile.mkdirs(); } ClassLoader cl = CommonUtils.class.getClassLoader(); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //load resource using my class loader or system class loader //Can happen if Launcher loaded by system class loader URL resource = cl != null ? cl.getResource(fileName) : ClassLoader.getSystemResource(fileName); if(resource == null) throw new NullPointerException("resource: " + fileName + " doesn't exist."); InputStream is = resource.openStream(); //buffer the streams to improve I/O performance final int bufferSize = 2048; bis = new BufferedInputStream(is, bufferSize); bos = new BufferedOutputStream(new FileOutputStream(newFile), bufferSize); byte[] buffer = new byte[bufferSize]; int c = 0; do { //read and write in chunks of buffer size until EOF reached c = bis.read(buffer, 0, bufferSize); if (c > 0) bos.write(buffer, 0, c); } while (c == bufferSize); //(# of bytes read)c will = bufferSize until EOF } catch(IOException e) { //if there is any error, delete any portion of file that did write newFile.delete(); } finally { if(bis != null) { try { bis.close(); } catch(IOException ignored) {} } if(bos != null) { try { bos.close(); } catch(IOException ignored) {} } } } /** * Replaces OS specific illegal characters from any filename with '_', * including ( / \n \r \t ) on all operating systems, ( ? * \ < > | " ) * on Windows, ( ` ) on unix. * * @param name the filename to check for illegal characters * @return String containing the cleaned filename */ public static String convertFileName(String name) { // ensure that block-characters aren't in the filename. name = I18NConvert.instance().compose(name); // if the name is too long, reduce it. We don't go all the way // up to 256 because we don't know how long the directory name is // We want to keep the extension, though. if(name.length() > 180) { int extStart = name.lastIndexOf('.'); if ( extStart == -1) { // no extension, wierd, but possible name = name.substring(0, 180); } else { // if extension is greater than 11, we concat it. // ( 11 = '.' + 10 extension characters ) int extLength = name.length() - extStart; int extEnd = extLength > 11 ? extStart + 11 : name.length(); name = name.substring(0, 180 - extLength) + name.substring(extStart, extEnd); } } for (int i = 0; i < ILLEGAL_CHARS_ANY_OS.length; i++) name = name.replace(ILLEGAL_CHARS_ANY_OS[i], '_'); if ( _isWindows || _isOS2 ) { for (int i = 0; i < ILLEGAL_CHARS_WINDOWS.length; i++) name = name.replace(ILLEGAL_CHARS_WINDOWS[i], '_'); } else if ( _isLinux || _isSolaris ) { for (int i = 0; i < ILLEGAL_CHARS_UNIX.length; i++) name = name.replace(ILLEGAL_CHARS_UNIX[i], '_'); } else if (_isMacOSX) { for(int i = 0; i < ILLEGAL_CHARS_MACOS.length; i++) name = name.replace(ILLEGAL_CHARS_MACOS[i], '_'); } return name; } /** * Converts a value in seconds to: * "d:hh:mm:ss" where d=days, hh=hours, mm=minutes, ss=seconds, or * "h:mm:ss" where h=hours<24, mm=minutes, ss=seconds, or * "m:ss" where m=minutes<60, ss=seconds */ public static String seconds2time(int seconds) { int minutes = seconds / 60; seconds = seconds - minutes * 60; int hours = minutes / 60; minutes = minutes - hours * 60; int days = hours / 24; hours = hours - days * 24; // build the numbers into a string StringBuffer time = new StringBuffer(); if (days != 0) { time.append(Integer.toString(days)); time.append(":"); if (hours < 10) time.append("0"); } if (days != 0 || hours != 0) { time.append(Integer.toString(hours)); time.append(":"); if (minutes < 10) time.append("0"); } time.append(Integer.toString(minutes)); time.append(":"); if (seconds < 10) time.append("0"); time.append(Integer.toString(seconds)); return time.toString(); } /** * Returns the stack traces of all current Threads or an empty * String if LimeWire is running on Java 1.4 or if an error * occured. */ public static String getAllStackTraces() { if (!CommonUtils.isJava15OrLater()) { return ""; } try { Method m = Thread.class.getDeclaredMethod("getAllStackTraces", new Class[0]); Map map = (Map)m.invoke(null, new Object[0]); List sorted = new ArrayList(map.entrySet()); Collections.sort(sorted, new Comparator() { public int compare(Object a, Object b) { Thread threadA = (Thread)((Map.Entry)a).getKey(); Thread threadB = (Thread)((Map.Entry)b).getKey(); return threadA.getName().compareTo(threadB.getName()); } }); StringBuffer buffer = new StringBuffer(); Iterator it = sorted.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); Thread key = (Thread)entry.getKey(); StackTraceElement[] value = (StackTraceElement[])entry.getValue(); buffer.append(key.getName()).append("\n"); for(int i = 0; i < value.length; i++) { buffer.append(" ").append(value[i]).append("\n"); } buffer.append("\n"); } // Remove the last '\n' if (buffer.length() > 0) { buffer.setLength(buffer.length()-1); } return buffer.toString(); } catch (Exception err) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println("An error occured during getting the StackTraces of all active Threads"); err.printStackTrace(pw); pw.flush(); return sw.toString(); } } /* public static void main(String args[]) { System.out.println("Is 1.3 or later? "+isJava13OrLater()); System.out.println("Is 1.4 or later? "+isJava14OrLater()); try { File src=new File("src.tmp"); File dst=new File("dst.tmp"); Assert.that(!src.exists() && !dst.exists(), "Temp files already exists"); write("abcdef", src); Assert.that(copy(src, dst)==true); Assert.that(equal(src, dst)); write("zxcvbnmn", src); Assert.that(copy(src, 3, dst)==3); write("zxc", src); Assert.that(equal(src, dst)); } catch (IOException e) { e.printStackTrace(); Assert.that(false); } // catch (InterruptedException e) { // e.printStackTrace(); // Assert.that(false); // } } private static void write(String txt, File f) throws IOException { BufferedOutputStream bos=new BufferedOutputStream( new FileOutputStream(f)); bos.write(txt.getBytes()); //who care about encoding? bos.flush(); bos.close(); } private static boolean equal(File f1, File f2) throws IOException { InputStream in1=new FileInputStream(f1); InputStream in2=new FileInputStream(f2); while (true) { int c1=in1.read(); int c2=in2.read(); if (c1!=c2) return false; if (c1==-1) break; } return true; } */ }