PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

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

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