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;
}
}