PageRenderTime 162ms CodeModel.GetById 48ms RepoModel.GetById 3ms app.codeStats 0ms

/core/com/limegroup/gnutella/util/CommonUtils.java

https://github.com/zootella/learning-bittorrent
Java | 1299 lines | 660 code | 147 blank | 492 comment | 136 complexity | bbce4f0153187ecc6d7cf421c0b300db MD5 | raw file
  1. package com.limegroup.gnutella.util;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.OutputStream;
  10. import java.io.PrintWriter;
  11. import java.io.StringWriter;
  12. import java.io.UnsupportedEncodingException;
  13. import java.lang.reflect.Method;
  14. import java.net.URL;
  15. import java.util.ArrayList;
  16. import java.util.Collections;
  17. import java.util.Comparator;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import java.util.Locale;
  21. import java.util.Map;
  22. import java.util.Properties;
  23. /**
  24. * This class handles common utility functions that many classes
  25. * may want to access.
  26. */
  27. //2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678|
  28. public final class CommonUtils {
  29. /**
  30. * Constant for the current version of LimeWire.
  31. */
  32. private static final String LIMEWIRE_VERSION = "@version@";
  33. /**
  34. * Variable used for testing only, it's value is set to whatever the test
  35. * needs, and getVersion method retuns this value if it's not null
  36. */
  37. private static String testVersion = null;
  38. /**
  39. * The cached value of the major revision number.
  40. */
  41. private static final int _majorVersionNumber =
  42. getMajorVersionNumberInternal(LIMEWIRE_VERSION);
  43. /**
  44. * The cached value of the minor revision number.
  45. */
  46. private static final int _minorVersionNumber =
  47. getMinorVersionNumberInternal(LIMEWIRE_VERSION);
  48. /**
  49. * The cached value of the really minor version number.
  50. */
  51. private static final int _serviceVersionNumber =
  52. getServiceVersionNumberInternal(LIMEWIRE_VERSION);
  53. /**
  54. * The cached value of the GUESS major revision number.
  55. */
  56. private static final int _guessMajorVersionNumber = 0;
  57. /**
  58. * The cached value of the GUESS minor revision number.
  59. */
  60. private static final int _guessMinorVersionNumber = 1;
  61. /**
  62. * The cached value of the Ultrapeer major revision number.
  63. */
  64. private static final int _upMajorVersionNumber = 0;
  65. /**
  66. * The cached value of the Ultrapeer minor revision number.
  67. */
  68. private static final int _upMinorVersionNumber = 1;
  69. /**
  70. * The vendor code for QHD and GWebCache. WARNING: to avoid character
  71. * encoding problems, this is hard-coded in QueryReply as well. So if you
  72. * change this, you must change QueryReply.
  73. */
  74. public static final String QHD_VENDOR_NAME = "LIME";
  75. /**
  76. * Constant for the java system properties.
  77. */
  78. private static final Properties PROPS = System.getProperties();
  79. /**
  80. * Variable for whether or not we're on Windows.
  81. */
  82. private static boolean _isWindows = false;
  83. /**
  84. * Variable for whether or not we're on Windows NT.
  85. */
  86. private static boolean _isWindowsNT = false;
  87. /**
  88. * Variable for whether or not we're on Windows XP.
  89. */
  90. private static boolean _isWindowsXP = false;
  91. /**
  92. * Variable for whether or not we're on Windows NT, 2000, or XP.
  93. */
  94. private static boolean _isWindowsNTor2000orXP = false;
  95. /**
  96. * Variable for whether or not we're on 2000 or XP.
  97. */
  98. private static boolean _isWindows2000orXP = false;
  99. /**
  100. * Variable for whether or not we're on Windows 95.
  101. */
  102. private static boolean _isWindows95 = false;
  103. /**
  104. * Variable for whether or not we're on Windows 98.
  105. */
  106. private static boolean _isWindows98 = false;
  107. /**
  108. * Variable for whether or not we're on Windows Me.
  109. */
  110. private static boolean _isWindowsMe = false;
  111. /**
  112. * Variable for whether or not the operating system allows the
  113. * application to be reduced to the system tray.
  114. */
  115. private static boolean _supportsTray = false;
  116. /**
  117. * Variable for whether or not we're on MacOSX.
  118. */
  119. private static boolean _isMacOSX = false;
  120. /**
  121. * Variable for whether or not we're on Linux.
  122. */
  123. private static boolean _isLinux = false;
  124. /**
  125. * Variable for whether or not we're on Solaris.
  126. */
  127. private static boolean _isSolaris = false;
  128. /**
  129. * Variable for whether or not we're on OS/2.
  130. */
  131. private static boolean _isOS2 = false;
  132. /**
  133. * Several arrays of illegal characters on various operating systems.
  134. * Used by convertFileName
  135. */
  136. private static final char[] ILLEGAL_CHARS_ANY_OS = {
  137. '/', '\n', '\r', '\t', '\0', '\f'
  138. };
  139. private static final char[] ILLEGAL_CHARS_UNIX = {'`'};
  140. private static final char[] ILLEGAL_CHARS_WINDOWS = {
  141. '?', '*', '\\', '<', '>', '|', '\"', ':'
  142. };
  143. private static final char[] ILLEGAL_CHARS_MACOS = {':'};
  144. /**
  145. * Cached constant for the HTTP Server: header value.
  146. */
  147. private static final String HTTP_SERVER;
  148. private static final String LIMEWIRE_PREFS_DIR_NAME = ".limewire";
  149. /**
  150. * Constant for the current running directory.
  151. */
  152. private static final File CURRENT_DIRECTORY =
  153. new File(PROPS.getProperty("user.dir"));
  154. /**
  155. * Variable for whether or not this is a PRO version of LimeWire.
  156. */
  157. private static boolean _isPro = false;
  158. /**
  159. * Variable for the settings directory.
  160. */
  161. static File SETTINGS_DIRECTORY = null;
  162. /**
  163. * Make sure the constructor can never be called.
  164. */
  165. private CommonUtils() {}
  166. /**
  167. * Initialize the settings statically.
  168. */
  169. static {
  170. setOperatingSystems();
  171. if(!LIMEWIRE_VERSION.endsWith("Pro")) {
  172. HTTP_SERVER = "LimeWire/" + LIMEWIRE_VERSION;
  173. }
  174. else {
  175. HTTP_SERVER = ("LimeWire/"+LIMEWIRE_VERSION.
  176. substring(0, LIMEWIRE_VERSION.length()-4)+" (Pro)");
  177. _isPro = true;
  178. }
  179. }
  180. /**
  181. * Sets the operating system variables.
  182. */
  183. private static void setOperatingSystems() {
  184. _isWindows = false;
  185. _isWindowsNTor2000orXP = false;
  186. _isWindows2000orXP = false;
  187. _isWindowsNT = false;
  188. _isWindowsXP = false;
  189. _isWindows95 = false;
  190. _isWindows98 = false;
  191. _isWindowsMe = false;
  192. _isSolaris = false;
  193. _isLinux = false;
  194. _isOS2 = false;
  195. _isMacOSX = false;
  196. String os = System.getProperty("os.name").toLowerCase(Locale.US);
  197. // set the operating system variables
  198. _isWindows = os.indexOf("windows") != -1;
  199. if (os.indexOf("windows nt") != -1 ||
  200. os.indexOf("windows 2000")!= -1 ||
  201. os.indexOf("windows xp")!= -1)
  202. _isWindowsNTor2000orXP = true;
  203. if (os.indexOf("windows 2000")!= -1 ||
  204. os.indexOf("windows xp")!= -1)
  205. _isWindows2000orXP = true;
  206. if (os.indexOf("windows nt") != -1)
  207. _isWindowsNT = true;
  208. if (os.indexOf("windows xp") != -1)
  209. _isWindowsXP = true;
  210. if(os.indexOf("windows 95") != -1)
  211. _isWindows95 = true;
  212. if(os.indexOf("windows 98") != -1)
  213. _isWindows98 = true;
  214. if(os.indexOf("windows me") != -1)
  215. _isWindowsMe = true;
  216. _isSolaris = os.indexOf("solaris") != -1;
  217. _isLinux = os.indexOf("linux") != -1;
  218. _isOS2 = os.indexOf("os/2") != -1;
  219. if(_isWindows || _isLinux) _supportsTray=true;
  220. if(os.startsWith("mac os")) {
  221. if(os.endsWith("x")) {
  222. _isMacOSX = true;
  223. }
  224. }
  225. }
  226. /** Gets the major version of GUESS supported.
  227. */
  228. public static int getGUESSMajorVersionNumber() {
  229. return _guessMajorVersionNumber;
  230. }
  231. /** Gets the minor version of GUESS supported.
  232. */
  233. public static int getGUESSMinorVersionNumber() {
  234. return _guessMinorVersionNumber;
  235. }
  236. /** Gets the major version of Ultrapeer Protocol supported.
  237. */
  238. public static int getUPMajorVersionNumber() {
  239. return _upMajorVersionNumber;
  240. }
  241. /** Gets the minor version of Ultrapeer Protocol supported.
  242. */
  243. public static int getUPMinorVersionNumber() {
  244. return _upMinorVersionNumber;
  245. }
  246. /**
  247. * Returns the current version number of LimeWire as
  248. * a string, e.g., "1.4".
  249. */
  250. public static String getLimeWireVersion() {
  251. if(testVersion==null)//Always the case, except when update tests are run
  252. return LIMEWIRE_VERSION;
  253. return testVersion;
  254. }
  255. /** Gets the major version of LimeWire.
  256. */
  257. public static int getMajorVersionNumber() {
  258. return _majorVersionNumber;
  259. }
  260. /** Gets the minor version of LimeWire.
  261. */
  262. public static int getMinorVersionNumber() {
  263. return _minorVersionNumber;
  264. }
  265. /** Gets the minor minor version of LimeWire.
  266. */
  267. public static int getServiceVersionNumber() {
  268. return _serviceVersionNumber;
  269. }
  270. static int getMajorVersionNumberInternal(String version) {
  271. if (!version.equals("@" + "version" + "@")) {
  272. try {
  273. int firstDot = version.indexOf(".");
  274. String majorStr = version.substring(0, firstDot);
  275. return new Integer(majorStr).intValue();
  276. }
  277. catch (NumberFormatException nfe) {
  278. }
  279. }
  280. // in case this is a mainline version or NFE was caught (strange)
  281. return 2;
  282. }
  283. /**
  284. * Accessor for whether or not this is LimeWire pro.
  285. *
  286. * @return <tt>true</tt> if it is pro, otherwise <tt>false</tt>
  287. */
  288. public static boolean isPro() {
  289. return _isPro;
  290. }
  291. /**
  292. * Accessor for whether or not this is a testing version
  293. * (@version@) of LimeWire.
  294. *
  295. * @return <tt>true</tt> if the version is @version@,
  296. * otherwise <tt>false</tt>
  297. */
  298. public static boolean isTestingVersion() {
  299. return LIMEWIRE_VERSION.equals("@" + "version" + "@");
  300. }
  301. static int getMinorVersionNumberInternal(String version) {
  302. if (!version.equals("@" + "version" + "@")) {
  303. try {
  304. int firstDot = version.indexOf(".");
  305. String minusMajor = version.substring(firstDot+1);
  306. int secondDot = minusMajor.indexOf(".");
  307. String minorStr = minusMajor.substring(0, secondDot);
  308. return new Integer(minorStr).intValue();
  309. }
  310. catch (NumberFormatException nfe) {
  311. }
  312. }
  313. // in case this is a mainline version or NFE was caught (strange)
  314. return 7;
  315. }
  316. static int getServiceVersionNumberInternal(String version) {
  317. if (!version.equals("@" + "version" + "@")) {
  318. try {
  319. int firstDot = version.indexOf(".");
  320. int secondDot = version.indexOf(".", firstDot+1);
  321. int p = secondDot+1;
  322. int q = p;
  323. while(q < version.length() &&
  324. Character.isDigit(version.charAt(q))) {
  325. q++;
  326. }
  327. if (p != q) {
  328. String service = version.substring(p, q);
  329. return new Integer(service).intValue();
  330. }
  331. }
  332. catch (NumberFormatException nfe) {
  333. }
  334. }
  335. // in case this is a mainline version or NFE was caught (strange)
  336. return 0;
  337. }
  338. /**
  339. * Returns a version number appropriate for upload headers.
  340. * Same as '"LimeWire "+getLimeWireVersion'.
  341. */
  342. public static String getVendor() {
  343. return "LimeWire " + LIMEWIRE_VERSION;
  344. }
  345. /**
  346. * Returns the string for the server that should be reported in the HTTP
  347. * "Server: " tag.
  348. *
  349. * @return the HTTP "Server: " header value
  350. */
  351. public static String getHttpServer() {
  352. return HTTP_SERVER;
  353. }
  354. /**
  355. * Returns the version of java we're using.
  356. */
  357. public static String getJavaVersion() {
  358. return PROPS.getProperty("java.version");
  359. }
  360. /**
  361. * Returns the operating system.
  362. */
  363. public static String getOS() {
  364. return PROPS.getProperty("os.name");
  365. }
  366. /**
  367. * Returns the operating system version.
  368. */
  369. public static String getOSVersion() {
  370. return PROPS.getProperty("os.version");
  371. }
  372. /**
  373. * Returns the user's current working directory as a <tt>File</tt>
  374. * instance, or <tt>null</tt> if the property is not set.
  375. *
  376. * @return the user's current working directory as a <tt>File</tt>
  377. * instance, or <tt>null</tt> if the property is not set
  378. */
  379. public static File getCurrentDirectory() {
  380. return CURRENT_DIRECTORY;
  381. }
  382. /**
  383. * Returns true if this is Windows NT or Windows 2000 and
  384. * hence can support a system tray feature.
  385. */
  386. public static boolean supportsTray() {
  387. return _supportsTray;
  388. }
  389. /**
  390. * Returns whether or not this operating system is considered
  391. * capable of meeting the requirements of a ultrapeer.
  392. *
  393. * @return <tt>true</tt> if this OS meets ultrapeer requirements,
  394. * <tt>false</tt> otherwise
  395. */
  396. public static boolean isUltrapeerOS() {
  397. return !(_isWindows98 || _isWindows95 || _isWindowsMe || _isWindowsNT);
  398. }
  399. /**
  400. * Returns whether or not the OS is some version of Windows.
  401. *
  402. * @return <tt>true</tt> if the application is running on some Windows
  403. * version, <tt>false</tt> otherwise
  404. */
  405. public static boolean isWindows() {
  406. return _isWindows;
  407. }
  408. /**
  409. * Returns whether or not the OS is Windows NT, 2000, or XP.
  410. *
  411. * @return <tt>true</tt> if the application is running on Windows NT,
  412. * 2000, or XP <tt>false</tt> otherwise
  413. */
  414. public static boolean isWindowsNTor2000orXP() {
  415. return _isWindowsNTor2000orXP;
  416. }
  417. /**
  418. * Returns whether or not the OS is 2000 or XP.
  419. *
  420. * @return <tt>true</tt> if the application is running on 2000 or XP,
  421. * <tt>false</tt> otherwise
  422. */
  423. public static boolean isWindows2000orXP() {
  424. return _isWindows2000orXP;
  425. }
  426. /**
  427. * Returns whether or not the OS is WinXP.
  428. *
  429. * @return <tt>true</tt> if the application is running on WinXP,
  430. * <tt>false</tt> otherwise
  431. */
  432. public static boolean isWindowsXP() {
  433. return _isWindowsXP;
  434. }
  435. /**
  436. * Returns whether or not the OS is OS/2.
  437. *
  438. * @return <tt>true</tt> if the application is running on OS/2,
  439. * <tt>false</tt> otherwise
  440. */
  441. public static boolean isOS2() {
  442. return _isOS2;
  443. }
  444. /**
  445. * Returns whether or not the OS is Mac OSX.
  446. *
  447. * @return <tt>true</tt> if the application is running on Mac OSX,
  448. * <tt>false</tt> otherwise
  449. */
  450. public static boolean isMacOSX() {
  451. return _isMacOSX;
  452. }
  453. /**
  454. * Returns whether or not the OS is Mac OSX 10.2 or above.
  455. *
  456. * @return <tt>true</tt> if the application is running on Mac OSX,
  457. * 10.2 or above, <tt>false</tt> otherwise
  458. */
  459. public static boolean isJaguarOrAbove() {
  460. if(!isMacOSX()) return false;
  461. return getOSVersion().startsWith("10.2");
  462. }
  463. /**
  464. * Returns whether or not the OS is Mac OSX 10.3 or above.
  465. *
  466. * @return <tt>true</tt> if the application is running on Mac OSX,
  467. * 10.3 or above, <tt>false</tt> otherwise
  468. */
  469. public static boolean isPantherOrAbove() {
  470. if(!isMacOSX()) return false;
  471. return getOSVersion().startsWith("10.3");
  472. }
  473. /**
  474. * Returns whether or not the Cocoa Foundation classes are available.
  475. */
  476. public static boolean isCocoaFoundationAvailable() {
  477. if(!isMacOSX())
  478. return false;
  479. try {
  480. Class.forName("com.apple.cocoa.foundation.NSUserDefaults");
  481. Class.forName("com.apple.cocoa.foundation.NSMutableDictionary");
  482. Class.forName("com.apple.cocoa.foundation.NSMutableArray");
  483. Class.forName("com.apple.cocoa.foundation.NSObject");
  484. Class.forName("com.apple.cocoa.foundation.NSSystem");
  485. return true;
  486. } catch(ClassNotFoundException error) {
  487. return false;
  488. } catch(NoClassDefFoundError error) {
  489. return false;
  490. }
  491. }
  492. /**
  493. * Returns wheather or not the Log4J library is available
  494. */
  495. public static boolean isLog4JAvailable() {
  496. try {
  497. Class.forName("org.apache.log4j.LogManager");
  498. return true;
  499. } catch (ClassNotFoundException ignore) {
  500. return false;
  501. } catch (NoClassDefFoundError ignore) {
  502. return false;
  503. }
  504. }
  505. /**
  506. * Returns whether or not the OS is any Mac OS.
  507. *
  508. * @return <tt>true</tt> if the application is running on Mac OSX
  509. * or any previous mac version, <tt>false</tt> otherwise
  510. */
  511. public static boolean isAnyMac() {
  512. return _isMacOSX;
  513. }
  514. /**
  515. * Returns whether or not the OS is Solaris.
  516. *
  517. * @return <tt>true</tt> if the application is running on Solaris,
  518. * <tt>false</tt> otherwise
  519. */
  520. public static boolean isSolaris() {
  521. return _isSolaris;
  522. }
  523. /**
  524. * Returns whether or not the OS is Linux.
  525. *
  526. * @return <tt>true</tt> if the application is running on Linux,
  527. * <tt>false</tt> otherwise
  528. */
  529. public static boolean isLinux() {
  530. return _isLinux;
  531. }
  532. /**
  533. * Returns whether or not the OS is some version of
  534. * Unix, defined here as only Solaris or Linux.
  535. */
  536. public static boolean isUnix() {
  537. return _isLinux || _isSolaris;
  538. }
  539. /**
  540. * Returns whether the OS is POSIX-like.
  541. */
  542. public static boolean isPOSIX() {
  543. return _isLinux || _isSolaris || _isMacOSX;
  544. }
  545. /**
  546. * Returns whether or not the current JVM is 1.4.x or later
  547. *
  548. * @return <tt>true</tt> if we are running on 1.4.x or later,
  549. * <tt>false</tt> otherwise
  550. */
  551. public static boolean isJava14OrLater() {
  552. String version=CommonUtils.getJavaVersion();
  553. return !version.startsWith("1.3")
  554. && !version.startsWith("1.2")
  555. && !version.startsWith("1.1")
  556. && !version.startsWith("1.0");
  557. }
  558. /**
  559. * Returns whether or not the current JVM is 1.4.x or later
  560. *
  561. * @return <tt>true</tt> if we are running on 1.4.x or later,
  562. * <tt>false</tt> otherwise
  563. */
  564. public static boolean isJava142OrLater() {
  565. String version = CommonUtils.getJavaVersion();
  566. return !version.startsWith("1.4.1")
  567. && !version.startsWith("1.4.0")
  568. && isJava14OrLater();
  569. }
  570. /**
  571. * Returns whether or not the current JVM is 1.5.x or later.
  572. */
  573. public static boolean isJava15OrLater() {
  574. String version=CommonUtils.getJavaVersion();
  575. return !version.startsWith("1.4")
  576. && !version.startsWith("1.3")
  577. && !version.startsWith("1.2")
  578. && !version.startsWith("1.1")
  579. && !version.startsWith("1.0");
  580. }
  581. /**
  582. * Determines if your version of java is out of date.
  583. */
  584. public static boolean isJavaOutOfDate() {
  585. return isWindows() &&
  586. !isSpecificJRE() &&
  587. (getJavaVersion().startsWith("1.3") ||
  588. getJavaVersion().startsWith("1.4.0"));
  589. }
  590. /**
  591. * Determines if this was loaded from a specific JRE.
  592. */
  593. public static boolean isSpecificJRE() {
  594. return new File(".", "jre").isDirectory();
  595. }
  596. /**
  597. * Attempts to copy the first 'amount' bytes of file 'src' to 'dst',
  598. * returning the number of bytes actually copied. If 'dst' already exists,
  599. * the copy may or may not succeed.
  600. *
  601. * @param src the source file to copy
  602. * @param amount the amount of src to copy, in bytes
  603. * @param dst the place to copy the file
  604. * @return the number of bytes actually copied. Returns 'amount' if the
  605. * entire requested range was copied.
  606. */
  607. public static int copy(File src, int amount, File dst) {
  608. final int BUFFER_SIZE=1024;
  609. int amountToRead=amount;
  610. InputStream in=null;
  611. OutputStream out=null;
  612. try {
  613. //I'm not sure whether buffering is needed here. It can't hurt.
  614. in=new BufferedInputStream(new FileInputStream(src));
  615. out=new BufferedOutputStream(new FileOutputStream(dst));
  616. byte[] buf=new byte[BUFFER_SIZE];
  617. while (amountToRead>0) {
  618. int read=in.read(buf, 0, Math.min(BUFFER_SIZE, amountToRead));
  619. if (read==-1)
  620. break;
  621. amountToRead-=read;
  622. out.write(buf, 0, read);
  623. }
  624. } catch (IOException e) {
  625. } finally {
  626. if (in!=null)
  627. try { in.close(); } catch (IOException e) { }
  628. if (out!=null) {
  629. try { out.flush(); } catch (IOException e) { }
  630. try { out.close(); } catch (IOException e) { }
  631. }
  632. }
  633. return amount-amountToRead;
  634. }
  635. /**
  636. * Copies the file 'src' to 'dst', returning true iff the copy succeeded.
  637. * If 'dst' already exists, the copy may or may not succeed. May also
  638. * fail for VERY large source files.
  639. */
  640. public static boolean copy(File src, File dst) {
  641. //Downcasting length can result in a sign change, causing
  642. //copy(File,int,File) to terminate immediately.
  643. long length=src.length();
  644. return copy(src, (int)length, dst)==length;
  645. }
  646. /**
  647. * Returns the user home directory.
  648. *
  649. * @return the <tt>File</tt> instance denoting the abstract pathname of
  650. * the user's home directory, or <tt>null</tt> if the home directory
  651. * does not exist
  652. */
  653. public static File getUserHomeDir() {
  654. return new File(PROPS.getProperty("user.home"));
  655. }
  656. /**
  657. * Return the user's name.
  658. *
  659. * @return the <tt>String</tt> denoting the user's name.
  660. */
  661. public static String getUserName() {
  662. return PROPS.getProperty("user.name");
  663. }
  664. private static synchronized void setUserSettingsDir(File settingsDir) throws IOException, SecurityException {
  665. settingsDir = settingsDir.getAbsoluteFile();
  666. if(!settingsDir.isDirectory()) {
  667. settingsDir.delete(); // delete whatever it may have been
  668. if(!settingsDir.mkdirs()) {
  669. String msg = "could not create preferences directory: "+
  670. settingsDir;
  671. throw new IOException(msg);
  672. }
  673. }
  674. if(!settingsDir.canWrite()) {
  675. throw new IOException("settings dir not writable");
  676. }
  677. if(!settingsDir.canRead()) {
  678. throw new IOException("settings dir not readable");
  679. }
  680. // make sure Windows files are moved
  681. moveWindowsFiles(settingsDir);
  682. // make sure old metadata files are moved
  683. moveXMLFiles(settingsDir);
  684. // cache the directory.
  685. SETTINGS_DIRECTORY = settingsDir;
  686. }
  687. /**
  688. * Returns the directory where all user settings should be stored. This
  689. * is where all application data should be stored. If the directory does
  690. * does not already exist, this attempts to create the directory, although
  691. * this is not guaranteed to succeed.
  692. *
  693. * @return the <tt>File</tt> instance denoting the user's home
  694. * directory for the application, or <tt>null</tt> if that directory
  695. * does not exist
  696. */
  697. public synchronized static File getUserSettingsDir() {
  698. if ( SETTINGS_DIRECTORY != null ) return SETTINGS_DIRECTORY;
  699. File settingsDir = new File(getUserHomeDir(),
  700. LIMEWIRE_PREFS_DIR_NAME);
  701. if (isWindows()) {
  702. String appdata = null;
  703. // In some Java 1.4 implementations, System.getenv() is
  704. // depricated with prejudice (throws java.lang.Error).
  705. if (isJava15OrLater()) {
  706. appdata = System.getProperty("LIMEWIRE_PREFS_DIR",
  707. System.getenv("APPDATA"));
  708. } else {
  709. // null string will fall back on default
  710. appdata = System.getProperty("LIMEWIRE_PREFS_DIR",null);
  711. }
  712. if ("%APPDATA%".equals(appdata)) {
  713. appdata = null; // fall back on default
  714. }
  715. if (appdata != null && appdata.length() > 0) {
  716. File tempSettingsDir = new File(appdata, "LimeWire");
  717. if (tempSettingsDir.isDirectory() || ! settingsDir.exists()) {
  718. try {
  719. setUserSettingsDir(tempSettingsDir);
  720. return tempSettingsDir;
  721. } catch (IOException e) {} // Ignore errors and fall back on default
  722. catch (SecurityException e) {} // Ignore errors and fall back on default
  723. }
  724. }
  725. } else if(isMacOSX()) {
  726. settingsDir = new File(getUserHomeDir(),
  727. "Library/Preferences/LimeWire");
  728. }
  729. // Default behavior
  730. try {
  731. setUserSettingsDir(settingsDir);
  732. } catch (IOException e) {
  733. throw new RuntimeException(e);
  734. }
  735. return settingsDir;
  736. }
  737. /**
  738. * Boolean for whether or not the windows files have been copied.
  739. */
  740. private static boolean _windowsFilesMoved = false;
  741. /**
  742. * Boolean for whether or not XML files have been copied.
  743. */
  744. private static boolean _xmlFilesMoved = false;
  745. /**
  746. * The array of files that should be stored in the user's home
  747. * directory.
  748. */
  749. private static final String[] USER_FILES = {
  750. "limewire.props",
  751. "gnutella.net",
  752. "fileurns.cache"
  753. };
  754. /**
  755. * On Windows, this copies files from the current directory to the
  756. * user's LimeWire home directory. The installer does not have
  757. * access to the user's home directory, so these files must be
  758. * copied. Note that they are only copied, however, if existing
  759. * files are not there. This ensures that the most recent files,
  760. * and the files that should be used, should always be saved in
  761. * the user's home LimeWire preferences directory.
  762. */
  763. private synchronized static void moveWindowsFiles(File settingsDir) {
  764. if(!isWindows()) return;
  765. if(_windowsFilesMoved) return;
  766. File currentDir = CommonUtils.getCurrentDirectory();
  767. for(int i=0; i<USER_FILES.length; i++) {
  768. File curUserFile = new File(settingsDir, USER_FILES[i]);
  769. File curDirFile = new File(currentDir, USER_FILES[i]);
  770. // if the file already exists in the user's home directory,
  771. // don't copy it
  772. if(curUserFile.isFile()) {
  773. continue;
  774. }
  775. if(!copy(curDirFile, curUserFile)) {
  776. throw new RuntimeException();
  777. }
  778. }
  779. _windowsFilesMoved = true;
  780. }
  781. /**
  782. * Old metadata definitions must be moved from ./lib/xml/data/*.*
  783. * This is done like the windows files copying, but for all files
  784. * in the data directory.
  785. */
  786. private synchronized static void moveXMLFiles(File settingsDir) {
  787. if(_xmlFilesMoved) return;
  788. // We must extend the currentDir & settingsDir to look
  789. // in the right places (lib/xml/data & xml/data).
  790. File currentDir = new File(
  791. CommonUtils.getCurrentDirectory().getPath() + "/lib/xml/data"
  792. );
  793. settingsDir = new File(settingsDir.getPath() + "/xml/data");
  794. settingsDir.mkdirs();
  795. String[] filesToMove = currentDir.list();
  796. if ( filesToMove != null ) {
  797. for(int i=0; i<filesToMove.length; i++) {
  798. File curUserFile = new File(settingsDir, filesToMove[i]);
  799. File curDirFile = new File(currentDir, filesToMove[i]);
  800. // if the file already exists in the user's home directory,
  801. // don't copy it
  802. if(curUserFile.isFile()) {
  803. continue;
  804. }
  805. copy(curDirFile, curUserFile);
  806. }
  807. }
  808. _xmlFilesMoved = true;
  809. }
  810. /**
  811. * Gets a resource file using the CommonUtils class loader,
  812. * or the system class loader if CommonUtils isn't loaded.
  813. */
  814. public static File getResourceFile(String location) {
  815. ClassLoader cl = CommonUtils.class.getClassLoader();
  816. URL resource = null;
  817. if(cl == null) {
  818. resource = ClassLoader.getSystemResource(location);
  819. } else {
  820. resource = cl.getResource(location);
  821. }
  822. if( resource == null ) {
  823. // note: this will probably not work,
  824. // but it will ultimately trigger a better exception
  825. // than returning null.
  826. return new File(location);
  827. }
  828. //NOTE: The resource URL will contain %20 instead of spaces.
  829. // This is by design, but will not work when trying to make a file.
  830. // See BugParadeID: 4466485
  831. //(http://developer.java.sun.com/developer/bugParade/bugs/4466485.html)
  832. // The recommended workaround is to use the URI class, but that doesn't
  833. // exist until Java 1.4. So, we can't use it here.
  834. // Thus, we manually have to parse out the %20s from the URL
  835. return new File( decode(resource.getFile()) );
  836. }
  837. /**
  838. * Gets an InputStream from a resource file.
  839. *
  840. * @param location the location of the resource in the resource file
  841. * @return an <tt>InputStream</tt> for the resource
  842. * @throws IOException if the resource could not be located or there was
  843. * another IO error accessing the resource
  844. */
  845. public static InputStream getResourceStream(String location)
  846. throws IOException {
  847. ClassLoader cl = CommonUtils.class.getClassLoader();
  848. URL resource = null;
  849. if(cl == null) {
  850. resource = ClassLoader.getSystemResource(location);
  851. } else {
  852. resource = cl.getResource(location);
  853. }
  854. if( resource == null)
  855. throw new IOException("null resource: "+location);
  856. else
  857. return resource.openStream();
  858. }
  859. /**
  860. * Copied from URLDecoder.java
  861. */
  862. public static String decode(String s) {
  863. StringBuffer sb = new StringBuffer();
  864. for(int i=0; i<s.length(); i++) {
  865. char c = s.charAt(i);
  866. switch (c) {
  867. case '+':
  868. sb.append(' ');
  869. break;
  870. case '%':
  871. try {
  872. sb.append((char)Integer.parseInt(
  873. s.substring(i+1,i+3),16));
  874. } catch (NumberFormatException e) {
  875. throw new IllegalArgumentException(s);
  876. }
  877. i += 2;
  878. break;
  879. default:
  880. sb.append(c);
  881. break;
  882. }
  883. }
  884. // Undo conversion to external encoding
  885. String result = sb.toString();
  886. try {
  887. byte[] inputBytes = result.getBytes("8859_1");
  888. result = new String(inputBytes);
  889. } catch (UnsupportedEncodingException e) {
  890. // The system should always have 8859_1
  891. }
  892. return result;
  893. }
  894. /**
  895. * Copies the specified resource file into the current directory from
  896. * the jar file. If the file already exists, no copy is performed.
  897. *
  898. * @param fileName the name of the file to copy, relative to the jar
  899. * file -- such as "com/limegroup/gnutella/gui/images/image.gif"
  900. */
  901. public static void copyResourceFile(final String fileName) {
  902. copyResourceFile(fileName, null);
  903. }
  904. /**
  905. * Copies the specified resource file into the current directory from
  906. * the jar file. If the file already exists, no copy is performed.
  907. *
  908. * @param fileName the name of the file to copy, relative to the jar
  909. * file -- such as "com/limegroup/gnutella/gui/images/image.gif"
  910. * @param newFile the new <tt>File</tt> instance where the resource file
  911. * will be copied to
  912. */
  913. public static void copyResourceFile(final String fileName, File newFile) {
  914. copyResourceFile(fileName, newFile, false);
  915. }
  916. /**
  917. * Copies the specified resource file into the current directory from
  918. * the jar file. If the file already exists, no copy is performed.
  919. *
  920. * @param fileName the name of the file to copy, relative to the jar
  921. * file -- such as "com/limegroup/gnutella/gui/images/image.gif"
  922. * @param newFile the new <tt>File</tt> instance where the resource file
  923. * will be copied to -- if this argument is null, the file will be
  924. * copied to the current directory
  925. * @param forceOverwrite specifies whether or not to overwrite the
  926. * file if it already exists
  927. */
  928. public static void copyResourceFile(final String fileName, File newFile,
  929. final boolean forceOverwrite) {
  930. if(newFile == null) newFile = new File(".", fileName);
  931. // return quickly if the file is already there, no copy necessary
  932. if( !forceOverwrite && newFile.exists() ) return;
  933. String parentString = newFile.getParent();
  934. if(parentString == null) {
  935. return;
  936. }
  937. File parentFile = new File(parentString);
  938. if(!parentFile.isDirectory()) {
  939. parentFile.mkdirs();
  940. }
  941. ClassLoader cl = CommonUtils.class.getClassLoader();
  942. BufferedInputStream bis = null;
  943. BufferedOutputStream bos = null;
  944. try {
  945. //load resource using my class loader or system class loader
  946. //Can happen if Launcher loaded by system class loader
  947. URL resource = cl != null
  948. ? cl.getResource(fileName)
  949. : ClassLoader.getSystemResource(fileName);
  950. if(resource == null)
  951. throw new NullPointerException("resource: " + fileName +
  952. " doesn't exist.");
  953. InputStream is = resource.openStream();
  954. //buffer the streams to improve I/O performance
  955. final int bufferSize = 2048;
  956. bis = new BufferedInputStream(is, bufferSize);
  957. bos =
  958. new BufferedOutputStream(new FileOutputStream(newFile),
  959. bufferSize);
  960. byte[] buffer = new byte[bufferSize];
  961. int c = 0;
  962. do { //read and write in chunks of buffer size until EOF reached
  963. c = bis.read(buffer, 0, bufferSize);
  964. if (c > 0)
  965. bos.write(buffer, 0, c);
  966. }
  967. while (c == bufferSize); //(# of bytes read)c will = bufferSize until EOF
  968. } catch(IOException e) {
  969. //if there is any error, delete any portion of file that did write
  970. newFile.delete();
  971. } finally {
  972. if(bis != null) {
  973. try {
  974. bis.close();
  975. } catch(IOException ignored) {}
  976. }
  977. if(bos != null) {
  978. try {
  979. bos.close();
  980. } catch(IOException ignored) {}
  981. }
  982. }
  983. }
  984. /**
  985. * Replaces OS specific illegal characters from any filename with '_',
  986. * including ( / \n \r \t ) on all operating systems, ( ? * \ < > | " )
  987. * on Windows, ( ` ) on unix.
  988. *
  989. * @param name the filename to check for illegal characters
  990. * @return String containing the cleaned filename
  991. */
  992. public static String convertFileName(String name) {
  993. // ensure that block-characters aren't in the filename.
  994. name = I18NConvert.instance().compose(name);
  995. // if the name is too long, reduce it. We don't go all the way
  996. // up to 256 because we don't know how long the directory name is
  997. // We want to keep the extension, though.
  998. if(name.length() > 180) {
  999. int extStart = name.lastIndexOf('.');
  1000. if ( extStart == -1) { // no extension, wierd, but possible
  1001. name = name.substring(0, 180);
  1002. } else {
  1003. // if extension is greater than 11, we concat it.
  1004. // ( 11 = '.' + 10 extension characters )
  1005. int extLength = name.length() - extStart;
  1006. int extEnd = extLength > 11 ? extStart + 11 : name.length();
  1007. name = name.substring(0, 180 - extLength) +
  1008. name.substring(extStart, extEnd);
  1009. }
  1010. }
  1011. for (int i = 0; i < ILLEGAL_CHARS_ANY_OS.length; i++)
  1012. name = name.replace(ILLEGAL_CHARS_ANY_OS[i], '_');
  1013. if ( _isWindows || _isOS2 ) {
  1014. for (int i = 0; i < ILLEGAL_CHARS_WINDOWS.length; i++)
  1015. name = name.replace(ILLEGAL_CHARS_WINDOWS[i], '_');
  1016. } else if ( _isLinux || _isSolaris ) {
  1017. for (int i = 0; i < ILLEGAL_CHARS_UNIX.length; i++)
  1018. name = name.replace(ILLEGAL_CHARS_UNIX[i], '_');
  1019. } else if (_isMacOSX) {
  1020. for(int i = 0; i < ILLEGAL_CHARS_MACOS.length; i++)
  1021. name = name.replace(ILLEGAL_CHARS_MACOS[i], '_');
  1022. }
  1023. return name;
  1024. }
  1025. /**
  1026. * Converts a value in seconds to:
  1027. * "d:hh:mm:ss" where d=days, hh=hours, mm=minutes, ss=seconds, or
  1028. * "h:mm:ss" where h=hours<24, mm=minutes, ss=seconds, or
  1029. * "m:ss" where m=minutes<60, ss=seconds
  1030. */
  1031. public static String seconds2time(int seconds) {
  1032. int minutes = seconds / 60;
  1033. seconds = seconds - minutes * 60;
  1034. int hours = minutes / 60;
  1035. minutes = minutes - hours * 60;
  1036. int days = hours / 24;
  1037. hours = hours - days * 24;
  1038. // build the numbers into a string
  1039. StringBuffer time = new StringBuffer();
  1040. if (days != 0) {
  1041. time.append(Integer.toString(days));
  1042. time.append(":");
  1043. if (hours < 10) time.append("0");
  1044. }
  1045. if (days != 0 || hours != 0) {
  1046. time.append(Integer.toString(hours));
  1047. time.append(":");
  1048. if (minutes < 10) time.append("0");
  1049. }
  1050. time.append(Integer.toString(minutes));
  1051. time.append(":");
  1052. if (seconds < 10) time.append("0");
  1053. time.append(Integer.toString(seconds));
  1054. return time.toString();
  1055. }
  1056. /**
  1057. * Returns the stack traces of all current Threads or an empty
  1058. * String if LimeWire is running on Java 1.4 or if an error
  1059. * occured.
  1060. */
  1061. public static String getAllStackTraces() {
  1062. if (!CommonUtils.isJava15OrLater()) {
  1063. return "";
  1064. }
  1065. try {
  1066. Method m = Thread.class.getDeclaredMethod("getAllStackTraces", new Class[0]);
  1067. Map map = (Map)m.invoke(null, new Object[0]);
  1068. List sorted = new ArrayList(map.entrySet());
  1069. Collections.sort(sorted, new Comparator() {
  1070. public int compare(Object a, Object b) {
  1071. Thread threadA = (Thread)((Map.Entry)a).getKey();
  1072. Thread threadB = (Thread)((Map.Entry)b).getKey();
  1073. return threadA.getName().compareTo(threadB.getName());
  1074. }
  1075. });
  1076. StringBuffer buffer = new StringBuffer();
  1077. Iterator it = sorted.iterator();
  1078. while(it.hasNext()) {
  1079. Map.Entry entry = (Map.Entry)it.next();
  1080. Thread key = (Thread)entry.getKey();
  1081. StackTraceElement[] value = (StackTraceElement[])entry.getValue();
  1082. buffer.append(key.getName()).append("\n");
  1083. for(int i = 0; i < value.length; i++) {
  1084. buffer.append(" ").append(value[i]).append("\n");
  1085. }
  1086. buffer.append("\n");
  1087. }
  1088. // Remove the last '\n'
  1089. if (buffer.length() > 0) {
  1090. buffer.setLength(buffer.length()-1);
  1091. }
  1092. return buffer.toString();
  1093. } catch (Exception err) {
  1094. StringWriter sw = new StringWriter();
  1095. PrintWriter pw = new PrintWriter(sw);
  1096. pw.println("An error occured during getting the StackTraces of all active Threads");
  1097. err.printStackTrace(pw);
  1098. pw.flush();
  1099. return sw.toString();
  1100. }
  1101. }
  1102. /*
  1103. public static void main(String args[]) {
  1104. System.out.println("Is 1.3 or later? "+isJava13OrLater());
  1105. System.out.println("Is 1.4 or later? "+isJava14OrLater());
  1106. try {
  1107. File src=new File("src.tmp");
  1108. File dst=new File("dst.tmp");
  1109. Assert.that(!src.exists() && !dst.exists(),
  1110. "Temp files already exists");
  1111. write("abcdef", src);
  1112. Assert.that(copy(src, dst)==true);
  1113. Assert.that(equal(src, dst));
  1114. write("zxcvbnmn", src);
  1115. Assert.that(copy(src, 3, dst)==3);
  1116. write("zxc", src);
  1117. Assert.that(equal(src, dst));
  1118. } catch (IOException e) {
  1119. e.printStackTrace();
  1120. Assert.that(false);
  1121. } // catch (InterruptedException e) {
  1122. // e.printStackTrace();
  1123. // Assert.that(false);
  1124. // }
  1125. }
  1126. private static void write(String txt, File f) throws IOException {
  1127. BufferedOutputStream bos=new BufferedOutputStream(
  1128. new FileOutputStream(f));
  1129. bos.write(txt.getBytes()); //who care about encoding?
  1130. bos.flush();
  1131. bos.close();
  1132. }
  1133. private static boolean equal(File f1, File f2) throws IOException {
  1134. InputStream in1=new FileInputStream(f1);
  1135. InputStream in2=new FileInputStream(f2);
  1136. while (true) {
  1137. int c1=in1.read();
  1138. int c2=in2.read();
  1139. if (c1!=c2)
  1140. return false;
  1141. if (c1==-1)
  1142. break;
  1143. }
  1144. return true;
  1145. }
  1146. */
  1147. }