package com.limegroup.gnutella.util; import com.limegroup.gnutella.settings.SharingSettings; 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.UnsupportedEncodingException; import java.net.URL; import java.util.Locale; 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 = "4.13.1"; /** * 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 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(); /** * 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 = {'`'}; /** * 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 the settings directory. */ /** * Make sure the constructor can never be called. */ private CommonUtils() {} /** * Initialize the settings statically. */ static { HTTP_SERVER = "LimeWire/" + LIMEWIRE_VERSION; } /** * 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 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 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; } /** * 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")); } /** * 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() { return SharingSettings.SETTINGS_DIRECTORY; } /** * 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], '_'); for (int i = 0; i < ILLEGAL_CHARS_UNIX.length; i++) name = name.replace(ILLEGAL_CHARS_UNIX[i], '_'); return name; } }