You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

FileUtils.java 57 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514
  1. /*
  2. * Copyright 2001-2005 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.util;
  18. import java.io.BufferedInputStream;
  19. import java.io.BufferedReader;
  20. import java.io.BufferedWriter;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileOutputStream;
  24. import java.io.FileReader;
  25. import java.io.FileWriter;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import java.io.InputStreamReader;
  29. import java.io.OutputStreamWriter;
  30. import java.io.Reader;
  31. import java.io.Writer;
  32. import java.io.OutputStream;
  33. import java.net.MalformedURLException;
  34. import java.net.URL;
  35. import java.text.CharacterIterator;
  36. import java.text.DecimalFormat;
  37. import java.text.StringCharacterIterator;
  38. import java.util.Random;
  39. import java.util.Stack;
  40. import java.util.StringTokenizer;
  41. import java.util.Vector;
  42. import org.apache.tools.ant.BuildException;
  43. import org.apache.tools.ant.Project;
  44. import org.apache.tools.ant.filters.util.ChainReaderHelper;
  45. import org.apache.tools.ant.taskdefs.condition.Os;
  46. import org.apache.tools.ant.types.FilterSetCollection;
  47. import org.apache.tools.ant.launch.Locator;
  48. /**
  49. * This class also encapsulates methods which allow Files to be
  50. * refered to using abstract path names which are translated to native
  51. * system file paths at runtime as well as copying files or setting
  52. * there last modification time.
  53. *
  54. * @version $Revision$
  55. */
  56. public class FileUtils {
  57. private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
  58. //get some non-crypto-grade randomness from various places.
  59. private static Random rand = new Random(System.currentTimeMillis()
  60. + Runtime.getRuntime().freeMemory());
  61. private static boolean onNetWare = Os.isFamily("netware");
  62. private static boolean onDos = Os.isFamily("dos");
  63. private static final int BUF_SIZE = 8192;
  64. // for toURI
  65. private static boolean[] isSpecial = new boolean[256];
  66. private static char[] escapedChar1 = new char[256];
  67. private static char[] escapedChar2 = new char[256];
  68. /**
  69. * the granularity of timestamps under FAT
  70. */
  71. public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
  72. /**
  73. * the granularity of timestamps under Unix
  74. */
  75. public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
  76. // stolen from FilePathToURI of the Xerces-J team
  77. static {
  78. for (int i = 0; i <= 0x20; i++) {
  79. isSpecial[i] = true;
  80. escapedChar1[i] = Character.forDigit(i >> 4, 16);
  81. escapedChar2[i] = Character.forDigit(i & 0xf, 16);
  82. }
  83. isSpecial[0x7f] = true;
  84. escapedChar1[0x7f] = '7';
  85. escapedChar2[0x7f] = 'F';
  86. char[] escChs = {'<', '>', '#', '%', '"', '{', '}',
  87. '|', '\\', '^', '~', '[', ']', '`'};
  88. int len = escChs.length;
  89. char ch;
  90. for (int i = 0; i < len; i++) {
  91. ch = escChs[i];
  92. isSpecial[ch] = true;
  93. escapedChar1[ch] = Character.forDigit(ch >> 4, 16);
  94. escapedChar2[ch] = Character.forDigit(ch & 0xf, 16);
  95. }
  96. }
  97. /**
  98. * Factory method.
  99. *
  100. * @return a new instance of FileUtils.
  101. * @deprecated Use getFileUtils instead, FileUtils do not have state.
  102. */
  103. public static FileUtils newFileUtils() {
  104. return new FileUtils();
  105. }
  106. /**
  107. * Method to retrieve The FileUtils, which is shared by all users of this
  108. * method.
  109. * @return an instance of FileUtils.
  110. * @since Ant 1.7
  111. */
  112. public static FileUtils getFileUtils() {
  113. return PRIMARY_INSTANCE;
  114. }
  115. /**
  116. * Empty constructor.
  117. */
  118. protected FileUtils() {
  119. }
  120. /**
  121. * Get the URL for a file taking into account # characters
  122. *
  123. * @param file the file whose URL representation is required.
  124. * @return The FileURL value
  125. * @throws MalformedURLException if the URL representation cannot be
  126. * formed.
  127. */
  128. public URL getFileURL(File file) throws MalformedURLException {
  129. return new URL(toURI(file.getAbsolutePath()));
  130. }
  131. /**
  132. * Convienence method to copy a file from a source to a destination.
  133. * No filtering is performed.
  134. *
  135. * @param sourceFile Name of file to copy from.
  136. * Must not be <code>null</code>.
  137. * @param destFile Name of file to copy to.
  138. * Must not be <code>null</code>.
  139. *
  140. * @throws IOException if the copying fails
  141. */
  142. public void copyFile(String sourceFile, String destFile)
  143. throws IOException {
  144. copyFile(new File(sourceFile), new File(destFile), null, false, false);
  145. }
  146. /**
  147. * Convienence method to copy a file from a source to a destination
  148. * specifying if token filtering must be used.
  149. *
  150. * @param sourceFile Name of file to copy from.
  151. * Must not be <code>null</code>.
  152. * @param destFile Name of file to copy to.
  153. * Must not be <code>null</code>.
  154. * @param filters the collection of filters to apply to this copy
  155. *
  156. * @throws IOException if the copying fails
  157. */
  158. public void copyFile(String sourceFile, String destFile,
  159. FilterSetCollection filters)
  160. throws IOException {
  161. copyFile(new File(sourceFile), new File(destFile), filters,
  162. false, false);
  163. }
  164. /**
  165. * Convienence method to copy a file from a source to a
  166. * destination specifying if token filtering must be used and if
  167. * source files may overwrite newer destination files.
  168. *
  169. * @param sourceFile Name of file to copy from.
  170. * Must not be <code>null</code>.
  171. * @param destFile Name of file to copy to.
  172. * Must not be <code>null</code>.
  173. * @param filters the collection of filters to apply to this copy
  174. * @param overwrite Whether or not the destination file should be
  175. * overwritten if it already exists.
  176. *
  177. * @throws IOException if the copying fails
  178. */
  179. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  180. boolean overwrite) throws IOException {
  181. copyFile(new File(sourceFile), new File(destFile), filters,
  182. overwrite, false);
  183. }
  184. /**
  185. * Convienence method to copy a file from a source to a
  186. * destination specifying if token filtering must be used, if
  187. * source files may overwrite newer destination files and the
  188. * last modified time of <code>destFile</code> file should be made equal
  189. * to the last modified time of <code>sourceFile</code>.
  190. *
  191. * @param sourceFile Name of file to copy from.
  192. * Must not be <code>null</code>.
  193. * @param destFile Name of file to copy to.
  194. * Must not be <code>null</code>.
  195. * @param filters the collection of filters to apply to this copy
  196. * @param overwrite Whether or not the destination file should be
  197. * overwritten if it already exists.
  198. * @param preserveLastModified Whether or not the last modified time of
  199. * the resulting file should be set to that
  200. * of the source file.
  201. *
  202. * @throws IOException if the copying fails
  203. */
  204. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  205. boolean overwrite, boolean preserveLastModified)
  206. throws IOException {
  207. copyFile(new File(sourceFile), new File(destFile), filters,
  208. overwrite, preserveLastModified);
  209. }
  210. /**
  211. * Convienence method to copy a file from a source to a
  212. * destination specifying if token filtering must be used, if
  213. * source files may overwrite newer destination files and the
  214. * last modified time of <code>destFile</code> file should be made equal
  215. * to the last modified time of <code>sourceFile</code>.
  216. *
  217. * @param sourceFile Name of file to copy from.
  218. * Must not be <code>null</code>.
  219. * @param destFile Name of file to copy to.
  220. * Must not be <code>null</code>.
  221. * @param filters the collection of filters to apply to this copy
  222. * @param overwrite Whether or not the destination file should be
  223. * overwritten if it already exists.
  224. * @param preserveLastModified Whether or not the last modified time of
  225. * the resulting file should be set to that
  226. * of the source file.
  227. * @param encoding the encoding used to read and write the files.
  228. *
  229. * @throws IOException if the copying fails
  230. *
  231. * @since Ant 1.5
  232. */
  233. public void copyFile(String sourceFile, String destFile,
  234. FilterSetCollection filters, boolean overwrite,
  235. boolean preserveLastModified, String encoding)
  236. throws IOException {
  237. copyFile(new File(sourceFile), new File(destFile), filters,
  238. overwrite, preserveLastModified, encoding);
  239. }
  240. /**
  241. * Convienence method to copy a file from a source to a
  242. * destination specifying if token filtering must be used, if
  243. * filter chains must be used, if source files may overwrite
  244. * newer destination files and the last modified time of
  245. * <code>destFile</code> file should be made equal
  246. * to the last modified time of <code>sourceFile</code>.
  247. *
  248. * @param sourceFile Name of file to copy from.
  249. * Must not be <code>null</code>.
  250. * @param destFile Name of file to copy to.
  251. * Must not be <code>null</code>.
  252. * @param filters the collection of filters to apply to this copy
  253. * @param filterChains filterChains to apply during the copy.
  254. * @param overwrite Whether or not the destination file should be
  255. * overwritten if it already exists.
  256. * @param preserveLastModified Whether or not the last modified time of
  257. * the resulting file should be set to that
  258. * of the source file.
  259. * @param encoding the encoding used to read and write the files.
  260. * @param project the project instance
  261. *
  262. * @throws IOException if the copying fails
  263. *
  264. * @since Ant 1.5
  265. */
  266. public void copyFile(String sourceFile, String destFile,
  267. FilterSetCollection filters, Vector filterChains,
  268. boolean overwrite, boolean preserveLastModified,
  269. String encoding, Project project)
  270. throws IOException {
  271. copyFile(new File(sourceFile), new File(destFile), filters,
  272. filterChains, overwrite, preserveLastModified,
  273. encoding, project);
  274. }
  275. /**
  276. * Convienence method to copy a file from a source to a
  277. * destination specifying if token filtering must be used, if
  278. * filter chains must be used, if source files may overwrite
  279. * newer destination files and the last modified time of
  280. * <code>destFile</code> file should be made equal
  281. * to the last modified time of <code>sourceFile</code>.
  282. *
  283. * @param sourceFile Name of file to copy from.
  284. * Must not be <code>null</code>.
  285. * @param destFile Name of file to copy to.
  286. * Must not be <code>null</code>.
  287. * @param filters the collection of filters to apply to this copy
  288. * @param filterChains filterChains to apply during the copy.
  289. * @param overwrite Whether or not the destination file should be
  290. * overwritten if it already exists.
  291. * @param preserveLastModified Whether or not the last modified time of
  292. * the resulting file should be set to that
  293. * of the source file.
  294. * @param inputEncoding the encoding used to read the files.
  295. * @param outputEncoding the encoding used to write the files.
  296. * @param project the project instance
  297. *
  298. * @throws IOException if the copying fails
  299. *
  300. * @since Ant 1.6
  301. */
  302. public void copyFile(String sourceFile, String destFile,
  303. FilterSetCollection filters, Vector filterChains,
  304. boolean overwrite, boolean preserveLastModified,
  305. String inputEncoding, String outputEncoding,
  306. Project project)
  307. throws IOException {
  308. copyFile(new File(sourceFile), new File(destFile), filters,
  309. filterChains, overwrite, preserveLastModified,
  310. inputEncoding, outputEncoding, project);
  311. }
  312. /**
  313. * Convienence method to copy a file from a source to a destination.
  314. * No filtering is performed.
  315. *
  316. * @param sourceFile the file to copy from.
  317. * Must not be <code>null</code>.
  318. * @param destFile the file to copy to.
  319. * Must not be <code>null</code>.
  320. *
  321. * @throws IOException if the copying fails
  322. */
  323. public void copyFile(File sourceFile, File destFile) throws IOException {
  324. copyFile(sourceFile, destFile, null, false, false);
  325. }
  326. /**
  327. * Convienence method to copy a file from a source to a destination
  328. * specifying if token filtering must be used.
  329. *
  330. * @param sourceFile the file to copy from.
  331. * Must not be <code>null</code>.
  332. * @param destFile the file to copy to.
  333. * Must not be <code>null</code>.
  334. * @param filters the collection of filters to apply to this copy
  335. *
  336. * @throws IOException if the copying fails
  337. */
  338. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters)
  339. throws IOException {
  340. copyFile(sourceFile, destFile, filters, false, false);
  341. }
  342. /**
  343. * Convienence method to copy a file from a source to a
  344. * destination specifying if token filtering must be used and if
  345. * source files may overwrite newer destination files.
  346. *
  347. * @param sourceFile the file to copy from.
  348. * Must not be <code>null</code>.
  349. * @param destFile the file to copy to.
  350. * Must not be <code>null</code>.
  351. * @param filters the collection of filters to apply to this copy
  352. * @param overwrite Whether or not the destination file should be
  353. * overwritten if it already exists.
  354. *
  355. * @throws IOException if the copying fails
  356. */
  357. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  358. boolean overwrite) throws IOException {
  359. copyFile(sourceFile, destFile, filters, overwrite, false);
  360. }
  361. /**
  362. * Convienence method to copy a file from a source to a
  363. * destination specifying if token filtering must be used, if
  364. * source files may overwrite newer destination files and the
  365. * last modified time of <code>destFile</code> file should be made equal
  366. * to the last modified time of <code>sourceFile</code>.
  367. *
  368. * @param sourceFile the file to copy from.
  369. * Must not be <code>null</code>.
  370. * @param destFile the file to copy to.
  371. * Must not be <code>null</code>.
  372. * @param filters the collection of filters to apply to this copy
  373. * @param overwrite Whether or not the destination file should be
  374. * overwritten if it already exists.
  375. * @param preserveLastModified Whether or not the last modified time of
  376. * the resulting file should be set to that
  377. * of the source file.
  378. *
  379. * @throws IOException if the copying fails
  380. */
  381. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  382. boolean overwrite, boolean preserveLastModified)
  383. throws IOException {
  384. copyFile(sourceFile, destFile, filters, overwrite,
  385. preserveLastModified, null);
  386. }
  387. /**
  388. * Convienence method to copy a file from a source to a
  389. * destination specifying if token filtering must be used, if
  390. * source files may overwrite newer destination files, the last
  391. * modified time of <code>destFile</code> file should be made
  392. * equal to the last modified time of <code>sourceFile</code> and
  393. * which character encoding to assume.
  394. *
  395. * @param sourceFile the file to copy from.
  396. * Must not be <code>null</code>.
  397. * @param destFile the file to copy to.
  398. * Must not be <code>null</code>.
  399. * @param filters the collection of filters to apply to this copy
  400. * @param overwrite Whether or not the destination file should be
  401. * overwritten if it already exists.
  402. * @param preserveLastModified Whether or not the last modified time of
  403. * the resulting file should be set to that
  404. * of the source file.
  405. * @param encoding the encoding used to read and write the files.
  406. *
  407. * @throws IOException if the copying fails
  408. *
  409. * @since Ant 1.5
  410. */
  411. public void copyFile(File sourceFile, File destFile,
  412. FilterSetCollection filters, boolean overwrite,
  413. boolean preserveLastModified, String encoding)
  414. throws IOException {
  415. copyFile(sourceFile, destFile, filters, null, overwrite,
  416. preserveLastModified, encoding, null);
  417. }
  418. /**
  419. * Convienence method to copy a file from a source to a
  420. * destination specifying if token filtering must be used, if
  421. * filter chains must be used, if source files may overwrite
  422. * newer destination files and the last modified time of
  423. * <code>destFile</code> file should be made equal
  424. * to the last modified time of <code>sourceFile</code>.
  425. *
  426. * @param sourceFile the file to copy from.
  427. * Must not be <code>null</code>.
  428. * @param destFile the file to copy to.
  429. * Must not be <code>null</code>.
  430. * @param filters the collection of filters to apply to this copy
  431. * @param filterChains filterChains to apply during the copy.
  432. * @param overwrite Whether or not the destination file should be
  433. * overwritten if it already exists.
  434. * @param preserveLastModified Whether or not the last modified time of
  435. * the resulting file should be set to that
  436. * of the source file.
  437. * @param encoding the encoding used to read and write the files.
  438. * @param project the project instance
  439. *
  440. * @throws IOException if the copying fails
  441. *
  442. * @since Ant 1.5
  443. */
  444. public void copyFile(File sourceFile, File destFile,
  445. FilterSetCollection filters, Vector filterChains,
  446. boolean overwrite, boolean preserveLastModified,
  447. String encoding, Project project)
  448. throws IOException {
  449. copyFile(sourceFile, destFile, filters, filterChains,
  450. overwrite, preserveLastModified, encoding, encoding, project);
  451. }
  452. /**
  453. * Convienence method to copy a file from a source to a
  454. * destination specifying if token filtering must be used, if
  455. * filter chains must be used, if source files may overwrite
  456. * newer destination files and the last modified time of
  457. * <code>destFile</code> file should be made equal
  458. * to the last modified time of <code>sourceFile</code>.
  459. *
  460. * @param sourceFile the file to copy from.
  461. * Must not be <code>null</code>.
  462. * @param destFile the file to copy to.
  463. * Must not be <code>null</code>.
  464. * @param filters the collection of filters to apply to this copy
  465. * @param filterChains filterChains to apply during the copy.
  466. * @param overwrite Whether or not the destination file should be
  467. * overwritten if it already exists.
  468. * @param preserveLastModified Whether or not the last modified time of
  469. * the resulting file should be set to that
  470. * of the source file.
  471. * @param inputEncoding the encoding used to read the files.
  472. * @param outputEncoding the encoding used to write the files.
  473. * @param project the project instance
  474. *
  475. *
  476. * @throws IOException if the copying fails
  477. *
  478. * @since Ant 1.6
  479. */
  480. public void copyFile(File sourceFile, File destFile,
  481. FilterSetCollection filters, Vector filterChains,
  482. boolean overwrite, boolean preserveLastModified,
  483. String inputEncoding, String outputEncoding,
  484. Project project)
  485. throws IOException {
  486. if (overwrite || !destFile.exists()
  487. || destFile.lastModified() < sourceFile.lastModified()) {
  488. if (destFile.exists() && destFile.isFile()) {
  489. destFile.delete();
  490. }
  491. // ensure that parent dir of dest file exists!
  492. // not using getParentFile method to stay 1.1 compat
  493. File parent = destFile.getParentFile();
  494. if (parent != null && !parent.exists()) {
  495. parent.mkdirs();
  496. }
  497. final boolean filterSetsAvailable = (filters != null
  498. && filters.hasFilters());
  499. final boolean filterChainsAvailable = (filterChains != null
  500. && filterChains.size() > 0);
  501. if (filterSetsAvailable) {
  502. BufferedReader in = null;
  503. BufferedWriter out = null;
  504. try {
  505. if (inputEncoding == null) {
  506. in = new BufferedReader(new FileReader(sourceFile));
  507. } else {
  508. InputStreamReader isr
  509. = new InputStreamReader(new FileInputStream(sourceFile),
  510. inputEncoding);
  511. in = new BufferedReader(isr);
  512. }
  513. if (outputEncoding == null) {
  514. out = new BufferedWriter(new FileWriter(destFile));
  515. } else {
  516. OutputStreamWriter osw
  517. = new OutputStreamWriter(new FileOutputStream(destFile),
  518. outputEncoding);
  519. out = new BufferedWriter(osw);
  520. }
  521. if (filterChainsAvailable) {
  522. ChainReaderHelper crh = new ChainReaderHelper();
  523. crh.setBufferSize(BUF_SIZE);
  524. crh.setPrimaryReader(in);
  525. crh.setFilterChains(filterChains);
  526. crh.setProject(project);
  527. Reader rdr = crh.getAssembledReader();
  528. in = new BufferedReader(rdr);
  529. }
  530. LineTokenizer lineTokenizer = new LineTokenizer();
  531. lineTokenizer.setIncludeDelims(true);
  532. String newline = null;
  533. String line = lineTokenizer.getToken(in);
  534. while (line != null) {
  535. if (line.length() == 0) {
  536. // this should not happen, because the lines are
  537. // returned with the end of line delimiter
  538. out.newLine();
  539. } else {
  540. newline = filters.replaceTokens(line);
  541. out.write(newline);
  542. }
  543. line = lineTokenizer.getToken(in);
  544. }
  545. } finally {
  546. close(out);
  547. close(in);
  548. }
  549. } else if (filterChainsAvailable
  550. || (inputEncoding != null
  551. && !inputEncoding.equals(outputEncoding))
  552. || (inputEncoding == null && outputEncoding != null)) {
  553. BufferedReader in = null;
  554. BufferedWriter out = null;
  555. try {
  556. if (inputEncoding == null) {
  557. in = new BufferedReader(new FileReader(sourceFile));
  558. } else {
  559. in =
  560. new BufferedReader(
  561. new InputStreamReader(
  562. new FileInputStream(sourceFile),
  563. inputEncoding));
  564. }
  565. if (outputEncoding == null) {
  566. out = new BufferedWriter(new FileWriter(destFile));
  567. } else {
  568. out =
  569. new BufferedWriter(
  570. new OutputStreamWriter(
  571. new FileOutputStream(destFile),
  572. outputEncoding));
  573. }
  574. if (filterChainsAvailable) {
  575. ChainReaderHelper crh = new ChainReaderHelper();
  576. crh.setBufferSize(BUF_SIZE);
  577. crh.setPrimaryReader(in);
  578. crh.setFilterChains(filterChains);
  579. crh.setProject(project);
  580. Reader rdr = crh.getAssembledReader();
  581. in = new BufferedReader(rdr);
  582. }
  583. char[] buffer = new char[BUF_SIZE];
  584. while (true) {
  585. int nRead = in.read(buffer, 0, buffer.length);
  586. if (nRead == -1) {
  587. break;
  588. }
  589. out.write(buffer, 0, nRead);
  590. }
  591. } finally {
  592. close(out);
  593. close(in);
  594. }
  595. } else {
  596. FileInputStream in = null;
  597. FileOutputStream out = null;
  598. try {
  599. in = new FileInputStream(sourceFile);
  600. out = new FileOutputStream(destFile);
  601. byte[] buffer = new byte[BUF_SIZE];
  602. int count = 0;
  603. do {
  604. out.write(buffer, 0, count);
  605. count = in.read(buffer, 0, buffer.length);
  606. } while (count != -1);
  607. } finally {
  608. close(out);
  609. close(in);
  610. }
  611. }
  612. if (preserveLastModified) {
  613. destFile.setLastModified(sourceFile.lastModified());
  614. }
  615. }
  616. }
  617. /**
  618. * Calls File.setLastModified(long time). Originally written to
  619. * to dynamically bind to that call on Java1.2+.
  620. *
  621. * @param file the file whose modified time is to be set
  622. * @param time the time to which the last modified time is to be set.
  623. * if this is -1, the current time is used.
  624. * @throws BuildException if the time cannot be set.
  625. */
  626. public void setFileLastModified(File file, long time)
  627. throws BuildException {
  628. if (time < 0) {
  629. time = System.currentTimeMillis();
  630. }
  631. file.setLastModified(time);
  632. }
  633. /**
  634. * Interpret the filename as a file relative to the given file -
  635. * unless the filename already represents an absolute filename.
  636. *
  637. * @param file the "reference" file for relative paths. This
  638. * instance must be an absolute file and must not contain
  639. * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
  640. * of /). If it is null, this call is equivalent to
  641. * <code>new java.io.File(filename)</code>.
  642. *
  643. * @param filename a file name
  644. *
  645. * @return an absolute file that doesn't contain &quot;./&quot; or
  646. * &quot;../&quot; sequences and uses the correct separator for
  647. * the current platform.
  648. */
  649. public File resolveFile(File file, String filename) {
  650. filename = filename.replace('/', File.separatorChar)
  651. .replace('\\', File.separatorChar);
  652. // deal with absolute files
  653. if (isAbsolutePath(filename)) {
  654. return normalize(filename);
  655. }
  656. if (file == null) {
  657. return new File(filename);
  658. }
  659. File helpFile = new File(file.getAbsolutePath());
  660. StringTokenizer tok = new StringTokenizer(filename, File.separator);
  661. while (tok.hasMoreTokens()) {
  662. String part = tok.nextToken();
  663. if (part.equals("..")) {
  664. helpFile = helpFile.getParentFile();
  665. if (helpFile == null) {
  666. String msg = "The file or path you specified ("
  667. + filename + ") is invalid relative to "
  668. + file.getPath();
  669. throw new BuildException(msg);
  670. }
  671. } else if (part.equals(".")) {
  672. // Do nothing here
  673. } else {
  674. helpFile = new File(helpFile, part);
  675. }
  676. }
  677. return new File(helpFile.getAbsolutePath());
  678. }
  679. /**
  680. * Verifies if the filename represents is an absolute path.
  681. * @param filename the file name to be checked for being an absolute path
  682. * @return true if the filename represents an absolute path.
  683. */
  684. private static boolean isAbsolutePath(String filename) {
  685. if (filename.startsWith(File.separator)) {
  686. // common for all os
  687. return true;
  688. } else if (onDos
  689. && filename.length() >= 2
  690. && Character.isLetter(filename.charAt(0))
  691. && filename.charAt(1) == ':') {
  692. // Actually on windows the : must be followed by a \ for
  693. // the path to be absolute, else the path is relative
  694. // to the current working directory on that drive.
  695. // (Every drive may have another current working directory)
  696. return true;
  697. } else if (onNetWare && filename.indexOf(":") > -1) {
  698. return true;
  699. }
  700. return false;
  701. }
  702. /**
  703. * &quot;normalize&quot; the given absolute path.
  704. *
  705. * <p>This includes:
  706. * <ul>
  707. * <li>Uppercase the drive letter if there is one.</li>
  708. * <li>Remove redundant slashes after the drive spec.</li>
  709. * <li>resolve all ./, .\, ../ and ..\ sequences.</li>
  710. * <li>DOS style paths that start with a drive letter will have
  711. * \ as the separator.</li>
  712. * </ul>
  713. * Unlike <code>File#getCanonicalPath()</code> it specifically doesn't
  714. * resolve symbolic links.
  715. *
  716. * @param path the path to be normalized
  717. * @return the normalized version of the path.
  718. *
  719. * @throws java.lang.NullPointerException if the file path is
  720. * equal to null.
  721. */
  722. public File normalize(String path) {
  723. String orig = path;
  724. path = path.replace('/', File.separatorChar)
  725. .replace('\\', File.separatorChar);
  726. // make sure we are dealing with an absolute path
  727. int colon = path.indexOf(":");
  728. if (!isAbsolutePath(path)) {
  729. String msg = path + " is not an absolute path";
  730. throw new BuildException(msg);
  731. }
  732. boolean dosWithDrive = false;
  733. String root = null;
  734. // Eliminate consecutive slashes after the drive spec
  735. if ((onDos && path.length() >= 2
  736. && Character.isLetter(path.charAt(0))
  737. && path.charAt(1) == ':')
  738. || (onNetWare && colon > -1)) {
  739. dosWithDrive = true;
  740. char[] ca = path.replace('/', '\\').toCharArray();
  741. StringBuffer sbRoot = new StringBuffer();
  742. for (int i = 0; i < colon; i++) {
  743. sbRoot.append(Character.toUpperCase(ca[i]));
  744. }
  745. sbRoot.append(':');
  746. if (colon + 1 < path.length()) {
  747. sbRoot.append(File.separatorChar);
  748. }
  749. root = sbRoot.toString();
  750. // Eliminate consecutive slashes after the drive spec
  751. StringBuffer sbPath = new StringBuffer();
  752. for (int i = colon + 1; i < ca.length; i++) {
  753. if ((ca[i] != '\\')
  754. || (ca[i] == '\\' && ca[i - 1] != '\\')) {
  755. sbPath.append(ca[i]);
  756. }
  757. }
  758. path = sbPath.toString().replace('\\', File.separatorChar);
  759. } else {
  760. if (path.length() == 1) {
  761. root = File.separator;
  762. path = "";
  763. } else if (path.charAt(1) == File.separatorChar) {
  764. // UNC drive
  765. root = File.separator + File.separator;
  766. path = path.substring(2);
  767. } else {
  768. root = File.separator;
  769. path = path.substring(1);
  770. }
  771. }
  772. Stack s = new Stack();
  773. s.push(root);
  774. StringTokenizer tok = new StringTokenizer(path, File.separator);
  775. while (tok.hasMoreTokens()) {
  776. String thisToken = tok.nextToken();
  777. if (".".equals(thisToken)) {
  778. continue;
  779. } else if ("..".equals(thisToken)) {
  780. if (s.size() < 2) {
  781. throw new BuildException("Cannot resolve path " + orig);
  782. } else {
  783. s.pop();
  784. }
  785. } else { // plain component
  786. s.push(thisToken);
  787. }
  788. }
  789. StringBuffer sb = new StringBuffer();
  790. for (int i = 0; i < s.size(); i++) {
  791. if (i > 1) {
  792. // not before the filesystem root and not after it, since root
  793. // already contains one
  794. sb.append(File.separatorChar);
  795. }
  796. sb.append(s.elementAt(i));
  797. }
  798. path = sb.toString();
  799. if (dosWithDrive) {
  800. path = path.replace('/', '\\');
  801. }
  802. return new File(path);
  803. }
  804. /**
  805. * Returns a VMS String representation of a <code>File</code> object.
  806. * This is useful since the JVM by default internally converts VMS paths
  807. * to Unix style.
  808. * The returned String is always an absolute path.
  809. *
  810. * @param f The <code>File</code> to get the VMS path for.
  811. * @return The absolute VMS path to <code>f</code>.
  812. */
  813. public String toVMSPath(File f) {
  814. // format: "DEVICE:[DIR.SUBDIR]FILE"
  815. String osPath;
  816. String path = normalize(f.getAbsolutePath()).getPath();
  817. String name = f.getName();
  818. boolean isAbsolute = path.charAt(0) == File.separatorChar;
  819. // treat directories specified using .DIR syntax as files
  820. boolean isDirectory = f.isDirectory()
  821. && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
  822. String device = null;
  823. StringBuffer directory = null;
  824. String file = null;
  825. int index = 0;
  826. if (isAbsolute) {
  827. index = path.indexOf(File.separatorChar, 1);
  828. if (index == -1) {
  829. return path.substring(1) + ":[000000]";
  830. } else {
  831. device = path.substring(1, index++);
  832. }
  833. }
  834. if (isDirectory) {
  835. directory = new StringBuffer(path.substring(index).
  836. replace(File.separatorChar, '.'));
  837. } else {
  838. int dirEnd =
  839. path.lastIndexOf(File.separatorChar, path.length());
  840. if (dirEnd == -1 || dirEnd < index) {
  841. file = path.substring(index);
  842. } else {
  843. directory = new StringBuffer(path.substring(index, dirEnd).
  844. replace(File.separatorChar, '.'));
  845. index = dirEnd + 1;
  846. if (path.length() > index) {
  847. file = path.substring(index);
  848. }
  849. }
  850. }
  851. if (!isAbsolute && directory != null) {
  852. directory.insert(0, '.');
  853. }
  854. osPath = ((device != null) ? device + ":" : "")
  855. + ((directory != null) ? "[" + directory + "]" : "")
  856. + ((file != null) ? file : "");
  857. return osPath;
  858. }
  859. /**
  860. * Create a temporary file in a given directory.
  861. *
  862. * <p>The file denoted by the returned abstract pathname did not
  863. * exist before this method was invoked, any subsequent invocation
  864. * of this method will yield a different file name.</p>
  865. * <p>
  866. * The filename is prefixNNNNNsuffix where NNNN is a random number
  867. * </p>
  868. * <p>This method is different to File.createTempFile of JDK 1.2
  869. * as it doesn't create the file itself.
  870. * It uses the location pointed to by java.io.tmpdir
  871. * when the parentDir attribute is
  872. * null.</p>
  873. *
  874. * @param prefix prefix before the random number
  875. * @param suffix file extension; include the '.'
  876. * @param parentDir Directory to create the temporary file in -
  877. * java.io.tmpdir used if not specificed
  878. *
  879. * @return a File reference to the new temporary file.
  880. * @since ant 1.5
  881. */
  882. public File createTempFile(String prefix, String suffix, File parentDir) {
  883. File result = null;
  884. String parent = System.getProperty("java.io.tmpdir");
  885. if (parentDir != null) {
  886. parent = parentDir.getPath();
  887. }
  888. DecimalFormat fmt = new DecimalFormat("#####");
  889. synchronized (rand) {
  890. do {
  891. result = new File(parent,
  892. prefix + fmt.format(Math.abs(rand.nextInt()))
  893. + suffix);
  894. } while (result.exists());
  895. }
  896. return result;
  897. }
  898. /**
  899. * Compares the contents of two files.
  900. *
  901. * @param f1 the file whose content is to be compared.
  902. * @param f2 the other file whose content is to be compared.
  903. *
  904. * @return true if the content of the files is the same.
  905. *
  906. * @throws IOException if the files cannot be read.
  907. */
  908. public boolean contentEquals(File f1, File f2) throws IOException {
  909. return contentEquals(f1, f2, false);
  910. }
  911. /**
  912. * Compares the contents of two files.
  913. *
  914. * @param f1 the file whose content is to be compared.
  915. * @param f2 the other file whose content is to be compared.
  916. * @param textfile true if the file is to be treated as a text file and
  917. * differences in kind of line break are to be ignored.
  918. *
  919. * @return true if the content of the files is the same.
  920. *
  921. * @throws IOException if the files cannot be read.
  922. * @since ant 1.7
  923. */
  924. public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException {
  925. if (f1.exists() != f2.exists()) {
  926. return false;
  927. }
  928. if (!f1.exists()) {
  929. // two not existing files are equal
  930. return true;
  931. }
  932. if (f1.isDirectory() || f2.isDirectory()) {
  933. // don't want to compare directory contents for now
  934. return false;
  935. }
  936. if (fileNameEquals(f1, f2)) {
  937. // same filename => true
  938. return true;
  939. }
  940. if (textfile) {
  941. return textEquals(f1, f2);
  942. } else {
  943. return binaryEquals(f1, f2);
  944. }
  945. }
  946. /**
  947. * Binary compares the contents of two files.
  948. * <p>
  949. * simple but sub-optimal comparision algorithm. written for working
  950. * rather than fast. Better would be a block read into buffers followed
  951. * by long comparisions apart from the final 1-7 bytes.
  952. * </p>
  953. *
  954. * @param f1 the file whose content is to be compared.
  955. * @param f2 the other file whose content is to be compared.
  956. * @return true if the content of the files is the same.
  957. * @throws IOException if the files cannot be read.
  958. */
  959. private boolean binaryEquals(File f1, File f2) throws IOException {
  960. if (f1.length() != f2.length()) {
  961. // different size =>false
  962. return false;
  963. }
  964. InputStream in1 = null;
  965. InputStream in2 = null;
  966. try {
  967. in1 = new BufferedInputStream(new FileInputStream(f1));
  968. in2 = new BufferedInputStream(new FileInputStream(f2));
  969. int expectedByte = in1.read();
  970. while (expectedByte != -1) {
  971. if (expectedByte != in2.read()) {
  972. return false;
  973. }
  974. expectedByte = in1.read();
  975. }
  976. if (in2.read() != -1) {
  977. return false;
  978. }
  979. return true;
  980. } finally {
  981. close(in1);
  982. close(in2);
  983. }
  984. }
  985. /**
  986. * Text compares the contents of two files.
  987. *
  988. * Ignores different kinds of line endings.
  989. *
  990. * @param f1 the file whose content is to be compared.
  991. * @param f2 the other file whose content is to be compared.
  992. * @return true if the content of the files is the same.
  993. * @throws IOException if the files cannot be read.
  994. */
  995. private boolean textEquals(File f1, File f2) throws IOException {
  996. BufferedReader in1 = null;
  997. BufferedReader in2 = null;
  998. try {
  999. in1 = new BufferedReader(new FileReader(f1));
  1000. in2 = new BufferedReader(new FileReader(f2));
  1001. String expected = in1.readLine();
  1002. while (expected != null) {
  1003. if (!expected.equals(in2.readLine())) {
  1004. return false;
  1005. }
  1006. expected = in1.readLine();
  1007. }
  1008. if (in2.readLine() != null) {
  1009. return false;
  1010. }
  1011. return true;
  1012. } finally {
  1013. close(in1);
  1014. close(in2);
  1015. }
  1016. }
  1017. /**
  1018. * This was originally an emulation of {@link File#getParentFile} for JDK 1.1,
  1019. * but it is now implemented using that method (Ant 1.7 onwards).
  1020. * @param f the file whose parent is required.
  1021. * @return the given file's parent, or null if the file does not have a
  1022. * parent.
  1023. * @since 1.10
  1024. * @deprecated Just use {@link File#getParentFile} directly.
  1025. */
  1026. public File getParentFile(File f) {
  1027. return (f == null) ? null : f.getParentFile();
  1028. }
  1029. /**
  1030. * Read from reader till EOF
  1031. * @param rdr the reader from which to read.
  1032. * @return the contents read out of the given reader
  1033. *
  1034. * @throws IOException if the contents could not be read out from the
  1035. * reader.
  1036. */
  1037. public static final String readFully(Reader rdr) throws IOException {
  1038. return readFully(rdr, BUF_SIZE);
  1039. }
  1040. /**
  1041. * Read from reader till EOF
  1042. *
  1043. * @param rdr the reader from which to read.
  1044. * @param bufferSize the buffer size to use when reading
  1045. *
  1046. * @return the contents read out of the given reader
  1047. *
  1048. * @throws IOException if the contents could not be read out from the
  1049. * reader.
  1050. */
  1051. public static final String readFully(Reader rdr, int bufferSize)
  1052. throws IOException {
  1053. if (bufferSize <= 0) {
  1054. throw new IllegalArgumentException("Buffer size must be greater "
  1055. + "than 0");
  1056. }
  1057. final char[] buffer = new char[bufferSize];
  1058. int bufferLength = 0;
  1059. StringBuffer textBuffer = null;
  1060. while (bufferLength != -1) {
  1061. bufferLength = rdr.read(buffer);
  1062. if (bufferLength > 0) {
  1063. textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer;
  1064. textBuffer.append(new String(buffer, 0, bufferLength));
  1065. }
  1066. }
  1067. return (textBuffer == null) ? null : textBuffer.toString();
  1068. }
  1069. /**
  1070. * This was originally an emulation of File.createNewFile for JDK 1.1,
  1071. * but it is now implemented using that method (Ant1.7 onwards).
  1072. *
  1073. * <p>This method has historically <strong>not</strong> guaranteed that the
  1074. * operation was atomic. In its current implementation it is.
  1075. *
  1076. * @param f the file to be created
  1077. * @return true if the file did not exist already.
  1078. * @throws IOException on error
  1079. * @since Ant 1.5
  1080. */
  1081. public boolean createNewFile(File f) throws IOException {
  1082. return createNewFile(f, false);
  1083. }
  1084. /**
  1085. * Create a new file, optionally creating parent directories.
  1086. *
  1087. * @param f the file to be created.
  1088. * @param mkdirs <code>boolean</code> whether to create parent directories.
  1089. * @return true if the file did not exist already.
  1090. * @throws IOException on error.
  1091. * @since Ant 1.6.3
  1092. */
  1093. public boolean createNewFile(File f, boolean mkdirs) throws IOException {
  1094. File parent = f.getParentFile();
  1095. if (mkdirs && !(parent.exists())) {
  1096. parent.mkdirs();
  1097. }
  1098. return f.createNewFile();
  1099. }
  1100. /**
  1101. * Checks whether a given file is a symbolic link.
  1102. *
  1103. * <p>It doesn't really test for symbolic links but whether the
  1104. * canonical and absolute paths of the file are identical - this
  1105. * may lead to false positives on some platforms.</p>
  1106. *
  1107. * @param parent the parent directory of the file to test
  1108. * @param name the name of the file to test.
  1109. *
  1110. * @return true if the file is a symbolic link.
  1111. * @throws IOException on error
  1112. * @since Ant 1.5
  1113. */
  1114. public boolean isSymbolicLink(File parent, String name)
  1115. throws IOException {
  1116. File resolvedParent = new File(parent.getCanonicalPath());
  1117. File toTest = new File(resolvedParent, name);
  1118. return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
  1119. }
  1120. /**
  1121. * Removes a leading path from a second path.
  1122. *
  1123. * @param leading The leading path, must not be null, must be absolute.
  1124. * @param path The path to remove from, must not be null, must be absolute.
  1125. *
  1126. * @return path's normalized absolute if it doesn't start with
  1127. * leading, path's path with leading's path removed otherwise.
  1128. *
  1129. * @since Ant 1.5
  1130. */
  1131. public String removeLeadingPath(File leading, File path) {
  1132. String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
  1133. String p = normalize(path.getAbsolutePath()).getAbsolutePath();
  1134. if (l.equals(p)) {
  1135. return "";
  1136. }
  1137. // ensure that l ends with a /
  1138. // so we never think /foo was a parent directory of /foobar
  1139. if (!l.endsWith(File.separator)) {
  1140. l += File.separator;
  1141. }
  1142. return (p.startsWith(l)) ? p.substring(l.length()) : p;
  1143. }
  1144. /**
  1145. * Constructs a <code>file:</code> URI that represents the
  1146. * external form of the given pathname.
  1147. *
  1148. * <p>Will be an absolute URI if the given path is absolute.</p>
  1149. *
  1150. * <p>This code doesn't handle non-ASCII characters properly.</p>
  1151. *
  1152. * @param path the path in the local file system
  1153. * @return the URI version of the local path.
  1154. * @since Ant 1.6
  1155. */
  1156. public String toURI(String path) {
  1157. boolean isDir = (new File(path)).isDirectory();
  1158. StringBuffer sb = new StringBuffer("file:");
  1159. // catch exception if normalize thinks this is not an absolute path
  1160. try {
  1161. path = normalize(path).getAbsolutePath();
  1162. sb.append("//");
  1163. // add an extra slash for filesystems with drive-specifiers
  1164. if (!path.startsWith(File.separator)) {
  1165. sb.append("/");
  1166. }
  1167. } catch (BuildException e) {
  1168. // relative path
  1169. }
  1170. path = path.replace('\\', '/');
  1171. CharacterIterator iter = new StringCharacterIterator(path);
  1172. for (char c = iter.first(); c != CharacterIterator.DONE;
  1173. c = iter.next()) {
  1174. if (c < 256 && isSpecial[c]) {
  1175. sb.append('%');
  1176. sb.append(escapedChar1[c]);
  1177. sb.append(escapedChar2[c]);
  1178. } else {
  1179. sb.append(c);
  1180. }
  1181. }
  1182. if (isDir && !path.endsWith("/")) {
  1183. sb.append('/');
  1184. }
  1185. return sb.toString();
  1186. }
  1187. /**
  1188. * Constructs a file path from a <code>file:</code> URI.
  1189. *
  1190. * <p>Will be an absolute path if the given URI is absolute.</p>
  1191. *
  1192. * <p>Swallows '%' that are not followed by two characters,
  1193. * doesn't deal with non-ASCII characters.</p>
  1194. *
  1195. * @param uri the URI designating a file in the local filesystem.
  1196. * @return the local file system path for the file.
  1197. * @since Ant 1.6
  1198. */
  1199. public String fromURI(String uri) {
  1200. String path = Locator.fromURI(uri);
  1201. // catch exception if normalize thinks this is not an absolute path
  1202. try {
  1203. path = normalize(path).getAbsolutePath();
  1204. } catch (BuildException e) {
  1205. // relative path
  1206. }
  1207. return path;
  1208. }
  1209. /**
  1210. * Compares two filenames.
  1211. *
  1212. * <p>Unlike java.io.File#equals this method will try to compare
  1213. * the absolute paths and &quot;normalize&quot; the filenames
  1214. * before comparing them.</p>
  1215. *
  1216. * @param f1 the file whose name is to be compared.
  1217. * @param f2 the other file whose name is to be compared.
  1218. *
  1219. * @return true if the file are for the same file.
  1220. *
  1221. * @since Ant 1.5.3
  1222. */
  1223. public boolean fileNameEquals(File f1, File f2) {
  1224. return normalize(f1.getAbsolutePath())
  1225. .equals(normalize(f2.getAbsolutePath()));
  1226. }
  1227. /**
  1228. * Renames a file, even if that involves crossing file system boundaries.
  1229. *
  1230. * <p>This will remove <code>to</code> (if it exists), ensure that
  1231. * <code>to</code>'s parent directory exists and move
  1232. * <code>from</code>, which involves deleting <code>from</code> as
  1233. * well.</p>
  1234. *
  1235. * @param from the file to move
  1236. * @param to the new file name
  1237. *
  1238. * @throws IOException if anything bad happens during this
  1239. * process. Note that <code>to</code> may have been deleted
  1240. * already when this happens.
  1241. *
  1242. * @since Ant 1.6
  1243. */
  1244. public void rename(File from, File to) throws IOException {
  1245. if (to.exists() && !to.delete()) {
  1246. throw new IOException("Failed to delete " + to
  1247. + " while trying to rename " + from);
  1248. }
  1249. File parent = to.getParentFile();
  1250. if (parent != null && !parent.exists() && !parent.mkdirs()) {
  1251. throw new IOException("Failed to create directory " + parent
  1252. + " while trying to rename " + from);
  1253. }
  1254. if (!from.renameTo(to)) {
  1255. copyFile(from, to);
  1256. if (!from.delete()) {
  1257. throw new IOException("Failed to delete " + from
  1258. + " while trying to rename it.");
  1259. }
  1260. }
  1261. }
  1262. /**
  1263. * get the granularity of file timestamps.
  1264. * The choice is made on OS, which is incorrect -it should really be
  1265. * by filesystem. We do not have an easy way to probe for file systems,
  1266. * however.
  1267. * @return the difference, in milliseconds, which two file timestamps must have
  1268. * in order for the two files to be given a creation order.
  1269. */
  1270. public long getFileTimestampGranularity() {
  1271. if (onDos) {
  1272. return FAT_FILE_TIMESTAMP_GRANULARITY;
  1273. } else {
  1274. return UNIX_FILE_TIMESTAMP_GRANULARITY;
  1275. }
  1276. }
  1277. /**
  1278. * Returns true if the source is older than the dest.
  1279. * If the dest file does not exist, then the test returns false; it is
  1280. * implicitly not up do date.
  1281. * @param source source file (should be the older)
  1282. * @param dest dest file (should be the newer)
  1283. * @param granularity an offset added to the source time.
  1284. * @return true if the source is older than the dest, taking the
  1285. * granularity into account
  1286. * @since Ant1.7
  1287. */
  1288. public boolean isUpToDate(File source, File dest, long granularity) {
  1289. //do a check for the destination file existing
  1290. if (!dest.exists()) {
  1291. //if it does not, then the file is not up to date.
  1292. return false;
  1293. }
  1294. long sourceTime = source.lastModified();
  1295. long destTime = dest.lastModified();
  1296. return isUpToDate(sourceTime, destTime, granularity);
  1297. }
  1298. /**
  1299. * returns true if the source is older than the dest
  1300. * @param source source file (should be the older)
  1301. * @param dest dest file (should be the newer)
  1302. * @return true if the source is older than the dest, taking the granularity into account
  1303. * @since Ant1.7
  1304. */
  1305. public boolean isUpToDate(File source, File dest) {
  1306. return isUpToDate(source, dest, getFileTimestampGranularity());
  1307. }
  1308. /**
  1309. * compare two timestamps for being up to date, use granularity too.,
  1310. *
  1311. * @param sourceTime timestamp of source file
  1312. * @param destTime timestamp of dest file
  1313. * @param granularity os/filesys granularity
  1314. * @return true if the dest file is considered up to date
  1315. */
  1316. public boolean isUpToDate(long sourceTime, long destTime, long granularity) {
  1317. if (destTime == -1) {
  1318. return false;
  1319. }
  1320. return destTime >= sourceTime + granularity;
  1321. }
  1322. /**
  1323. * compare two timestamps for being up to date, use the
  1324. * current granularity
  1325. *
  1326. * @param sourceTime timestamp of source file
  1327. * @param destTime timestamp of dest file
  1328. * @return true if the dest file is considered up to date
  1329. */
  1330. public boolean isUpToDate(long sourceTime, long destTime) {
  1331. return isUpToDate(sourceTime, destTime, getFileTimestampGranularity());
  1332. }
  1333. /**
  1334. * close a writer without throwing any exception if something went wrong.
  1335. * Do not attempt to close it if the file is null
  1336. * @param device output writer, can be null
  1337. */
  1338. public static void close(Writer device) {
  1339. if (device != null) {
  1340. try {
  1341. device.close();
  1342. } catch (IOException ioex) {
  1343. //ignore
  1344. }
  1345. }
  1346. }
  1347. /**
  1348. * close a stream without throwing any exception if something went wrong.
  1349. * Do not attempt to close it if the file is null
  1350. *
  1351. * @param device stream, can be null
  1352. */
  1353. public static void close(Reader device) {
  1354. if (device != null) {
  1355. try {
  1356. device.close();
  1357. } catch (IOException ioex) {
  1358. //ignore
  1359. }
  1360. }
  1361. }
  1362. /**
  1363. * close a stream without throwing any exception if something went wrong.
  1364. * Do not attempt to close it if the file is null
  1365. *
  1366. * @param device stream, can be null
  1367. */
  1368. public static void close(OutputStream device) {
  1369. if (device != null) {
  1370. try {
  1371. device.close();
  1372. } catch (IOException ioex) {
  1373. //ignore
  1374. }
  1375. }
  1376. }
  1377. /**
  1378. * close a stream without throwing any exception if something went wrong.
  1379. * Do not attempt to close it if the file is null
  1380. *
  1381. * @param device stream, can be null
  1382. */
  1383. public static void close(InputStream device) {
  1384. if (device != null) {
  1385. try {
  1386. device.close();
  1387. } catch (IOException ioex) {
  1388. //ignore
  1389. }
  1390. }
  1391. }
  1392. /**
  1393. * Delete the file with {@link File#delete()} if the argument is not null.
  1394. * Do nothing on a null argument
  1395. * @param file file to delete
  1396. */
  1397. public static void delete(File file) {
  1398. if (file != null) {
  1399. file.delete();
  1400. }
  1401. }
  1402. }