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 64 kB

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