KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > util > FileUtils


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.util;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.InputStreamReader JavaDoc;
25 import java.io.Reader JavaDoc;
26 import java.io.UnsupportedEncodingException JavaDoc;
27 import java.io.Writer JavaDoc;
28 import java.io.OutputStream JavaDoc;
29 import java.net.MalformedURLException JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.text.DecimalFormat JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.List JavaDoc;
36 import java.util.Random JavaDoc;
37 import java.util.Stack JavaDoc;
38 import java.util.StringTokenizer JavaDoc;
39 import java.util.Vector JavaDoc;
40 import org.apache.tools.ant.BuildException;
41 import org.apache.tools.ant.PathTokenizer;
42 import org.apache.tools.ant.Project;
43 import org.apache.tools.ant.taskdefs.condition.Os;
44 import org.apache.tools.ant.types.FilterSetCollection;
45 import org.apache.tools.ant.types.resources.FileResource;
46 import org.apache.tools.ant.launch.Locator;
47
48 /**
49  * This class also encapsulates methods which allow Files to be
50  * referred to using abstract path names which are translated to native
51  * system file paths at runtime as well as copying files or setting
52  * their last modification time.
53  *
54  */

55 public class FileUtils {
56
57     private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
58
59     //get some non-crypto-grade randomness from various places.
60
private static Random JavaDoc rand = new Random JavaDoc(System.currentTimeMillis()
61             + Runtime.getRuntime().freeMemory());
62
63     private static boolean onNetWare = Os.isFamily("netware");
64     private static boolean onDos = Os.isFamily("dos");
65     private static boolean onWin9x = Os.isFamily("win9x");
66     private static boolean onWindows = Os.isFamily("windows");
67
68     static final int BUF_SIZE = 8192;
69
70
71     /**
72      * The granularity of timestamps under FAT.
73      */

74     public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
75
76     /**
77      * The granularity of timestamps under Unix.
78      */

79     public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
80
81     /**
82      * The granularity of timestamps under the NT File System.
83      * NTFS has a granularity of 100 nanoseconds, which is less
84      * than 1 millisecond, so we round this up to 1 millisecond.
85      */

86     public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1;
87
88
89     /**
90      * A one item cache for fromUri.
91      * fromUri is called for each element when parseing ant build
92      * files. It is a costly operation. This just caches the result
93      * of the last call.
94      */

95     private Object JavaDoc cacheFromUriLock = new Object JavaDoc();
96     private String JavaDoc cacheFromUriRequest = null;
97     private String JavaDoc cacheFromUriResponse = null;
98
99     /**
100      * Factory method.
101      *
102      * @return a new instance of FileUtils.
103      * @deprecated since 1.7.
104      * Use getFileUtils instead,
105      * FileUtils do not have state.
106      */

107     public static FileUtils newFileUtils() {
108         return new FileUtils();
109     }
110
111     /**
112      * Method to retrieve The FileUtils, which is shared by all users of this
113      * method.
114      * @return an instance of FileUtils.
115      * @since Ant 1.6.3
116      */

117     public static FileUtils getFileUtils() {
118         return PRIMARY_INSTANCE;
119     }
120
121     /**
122      * Empty constructor.
123      */

124     protected FileUtils() {
125     }
126
127     /**
128      * Get the URL for a file taking into account # characters.
129      *
130      * @param file the file whose URL representation is required.
131      * @return The FileURL value.
132      * @throws MalformedURLException if the URL representation cannot be
133      * formed.
134      */

135     public URL JavaDoc getFileURL(File JavaDoc file) throws MalformedURLException JavaDoc {
136         return new URL JavaDoc(toURI(file.getAbsolutePath()));
137     }
138
139     /**
140      * Convenience method to copy a file from a source to a destination.
141      * No filtering is performed.
142      *
143      * @param sourceFile Name of file to copy from.
144      * Must not be <code>null</code>.
145      * @param destFile Name of file to copy to.
146      * Must not be <code>null</code>.
147      *
148      * @throws IOException if the copying fails.
149      */

150     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile)
151         throws IOException JavaDoc {
152         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), null, false, false);
153     }
154
155     /**
156      * Convenience method to copy a file from a source to a destination
157      * specifying if token filtering must be used.
158      *
159      * @param sourceFile Name of file to copy from.
160      * Must not be <code>null</code>.
161      * @param destFile Name of file to copy to.
162      * Must not be <code>null</code>.
163      * @param filters the collection of filters to apply to this copy.
164      *
165      * @throws IOException if the copying fails.
166      */

167     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile,
168                          FilterSetCollection filters)
169         throws IOException JavaDoc {
170         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), filters,
171                  false, false);
172     }
173
174     /**
175      * Convenience method to copy a file from a source to a
176      * destination specifying if token filtering must be used and if
177      * source files may overwrite newer destination files.
178      *
179      * @param sourceFile Name of file to copy from.
180      * Must not be <code>null</code>.
181      * @param destFile Name of file to copy to.
182      * Must not be <code>null</code>.
183      * @param filters the collection of filters to apply to this copy.
184      * @param overwrite Whether or not the destination file should be
185      * overwritten if it already exists.
186      *
187      * @throws IOException if the copying fails.
188      */

189     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile, FilterSetCollection filters,
190                          boolean overwrite) throws IOException JavaDoc {
191         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), filters,
192                  overwrite, false);
193     }
194
195     /**
196      * Convenience method to copy a file from a source to a
197      * destination specifying if token filtering must be used, if
198      * source files may overwrite newer destination files and the
199      * last modified time of <code>destFile</code> file should be made equal
200      * to the last modified time of <code>sourceFile</code>.
201      *
202      * @param sourceFile Name of file to copy from.
203      * Must not be <code>null</code>.
204      * @param destFile Name of file to copy to.
205      * Must not be <code>null</code>.
206      * @param filters the collection of filters to apply to this copy.
207      * @param overwrite Whether or not the destination file should be
208      * overwritten if it already exists.
209      * @param preserveLastModified Whether or not the last modified time of
210      * the resulting file should be set to that
211      * of the source file.
212      *
213      * @throws IOException if the copying fails.
214      */

215     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile, FilterSetCollection filters,
216                          boolean overwrite, boolean preserveLastModified)
217         throws IOException JavaDoc {
218         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), filters,
219                  overwrite, preserveLastModified);
220     }
221
222     /**
223      * Convenience method to copy a file from a source to a
224      * destination specifying if token filtering must be used, if
225      * source files may overwrite newer destination files and the
226      * last modified time of <code>destFile</code> file should be made equal
227      * to the last modified time of <code>sourceFile</code>.
228      *
229      * @param sourceFile Name of file to copy from.
230      * Must not be <code>null</code>.
231      * @param destFile Name of file to copy to.
232      * Must not be <code>null</code>.
233      * @param filters the collection of filters to apply to this copy.
234      * @param overwrite Whether or not the destination file should be
235      * overwritten if it already exists.
236      * @param preserveLastModified Whether or not the last modified time of
237      * the resulting file should be set to that
238      * of the source file.
239      * @param encoding the encoding used to read and write the files.
240      *
241      * @throws IOException if the copying fails.
242      *
243      * @since Ant 1.5
244      */

245     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile,
246                          FilterSetCollection filters, boolean overwrite,
247                          boolean preserveLastModified, String JavaDoc encoding)
248         throws IOException JavaDoc {
249         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), filters,
250                  overwrite, preserveLastModified, encoding);
251     }
252
253     // CheckStyle:ParameterNumberCheck OFF - bc
254
/**
255      * Convenience method to copy a file from a source to a
256      * destination specifying if token filtering must be used, if
257      * filter chains must be used, if source files may overwrite
258      * newer destination files and the last modified time of
259      * <code>destFile</code> file should be made equal
260      * to the last modified time of <code>sourceFile</code>.
261      *
262      * @param sourceFile Name of file to copy from.
263      * Must not be <code>null</code>.
264      * @param destFile Name of file to copy to.
265      * Must not be <code>null</code>.
266      * @param filters the collection of filters to apply to this copy.
267      * @param filterChains filterChains to apply during the copy.
268      * @param overwrite Whether or not the destination file should be
269      * overwritten if it already exists.
270      * @param preserveLastModified Whether or not the last modified time of
271      * the resulting file should be set to that
272      * of the source file.
273      * @param encoding the encoding used to read and write the files.
274      * @param project the project instance.
275      *
276      * @throws IOException if the copying fails.
277      *
278      * @since Ant 1.5
279      */

280     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile,
281                          FilterSetCollection filters, Vector JavaDoc filterChains,
282                          boolean overwrite, boolean preserveLastModified,
283                          String JavaDoc encoding, Project project)
284         throws IOException JavaDoc {
285         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), filters,
286                  filterChains, overwrite, preserveLastModified,
287                  encoding, project);
288     }
289
290     /**
291      * Convenience method to copy a file from a source to a
292      * destination specifying if token filtering must be used, if
293      * filter chains must be used, if source files may overwrite
294      * newer destination files and the last modified time of
295      * <code>destFile</code> file should be made equal
296      * to the last modified time of <code>sourceFile</code>.
297      *
298      * @param sourceFile Name of file to copy from.
299      * Must not be <code>null</code>.
300      * @param destFile Name of file to copy to.
301      * Must not be <code>null</code>.
302      * @param filters the collection of filters to apply to this copy.
303      * @param filterChains filterChains to apply during the copy.
304      * @param overwrite Whether or not the destination file should be
305      * overwritten if it already exists.
306      * @param preserveLastModified Whether or not the last modified time of
307      * the resulting file should be set to that
308      * of the source file.
309      * @param inputEncoding the encoding used to read the files.
310      * @param outputEncoding the encoding used to write the files.
311      * @param project the project instance.
312      *
313      * @throws IOException if the copying fails.
314      *
315      * @since Ant 1.6
316      */

317     public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile,
318                          FilterSetCollection filters, Vector JavaDoc filterChains,
319                          boolean overwrite, boolean preserveLastModified,
320                          String JavaDoc inputEncoding, String JavaDoc outputEncoding,
321                          Project project)
322         throws IOException JavaDoc {
323         copyFile(new File JavaDoc(sourceFile), new File JavaDoc(destFile), filters,
324                  filterChains, overwrite, preserveLastModified,
325                  inputEncoding, outputEncoding, project);
326     }
327
328     /**
329      * Convenience method to copy a file from a source to a destination.
330      * No filtering is performed.
331      *
332      * @param sourceFile the file to copy from.
333      * Must not be <code>null</code>.
334      * @param destFile the file to copy to.
335      * Must not be <code>null</code>.
336      *
337      * @throws IOException if the copying fails.
338      */

339     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile) throws IOException JavaDoc {
340         copyFile(sourceFile, destFile, null, false, false);
341     }
342
343     /**
344      * Convenience method to copy a file from a source to a destination
345      * specifying if token filtering must be used.
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      *
353      * @throws IOException if the copying fails.
354      */

355     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile, FilterSetCollection filters)
356         throws IOException JavaDoc {
357         copyFile(sourceFile, destFile, filters, false, false);
358     }
359
360     /**
361      * Convenience method to copy a file from a source to a
362      * destination specifying if token filtering must be used and if
363      * source files may overwrite newer destination files.
364      *
365      * @param sourceFile the file to copy from.
366      * Must not be <code>null</code>.
367      * @param destFile the file to copy to.
368      * Must not be <code>null</code>.
369      * @param filters the collection of filters to apply to this copy.
370      * @param overwrite Whether or not the destination file should be
371      * overwritten if it already exists.
372      *
373      * @throws IOException if the copying fails.
374      */

375     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile, FilterSetCollection filters,
376                          boolean overwrite) throws IOException JavaDoc {
377         copyFile(sourceFile, destFile, filters, overwrite, false);
378     }
379
380     /**
381      * Convenience method to copy a file from a source to a
382      * destination specifying if token filtering must be used, if
383      * source files may overwrite newer destination files and the
384      * last modified time of <code>destFile</code> file should be made equal
385      * to the last modified time of <code>sourceFile</code>.
386      *
387      * @param sourceFile the file to copy from.
388      * Must not be <code>null</code>.
389      * @param destFile the file to copy to.
390      * Must not be <code>null</code>.
391      * @param filters the collection of filters to apply to this copy.
392      * @param overwrite Whether or not the destination file should be
393      * overwritten if it already exists.
394      * @param preserveLastModified Whether or not the last modified time of
395      * the resulting file should be set to that
396      * of the source file.
397      *
398      * @throws IOException if the copying fails.
399      */

400     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile, FilterSetCollection filters,
401                          boolean overwrite, boolean preserveLastModified)
402         throws IOException JavaDoc {
403         copyFile(sourceFile, destFile, filters, overwrite,
404                  preserveLastModified, null);
405     }
406
407     /**
408      * Convenience method to copy a file from a source to a
409      * destination specifying if token filtering must be used, if
410      * source files may overwrite newer destination files, the last
411      * modified time of <code>destFile</code> file should be made
412      * equal to the last modified time of <code>sourceFile</code> and
413      * which character encoding to assume.
414      *
415      * @param sourceFile the file to copy from.
416      * Must not be <code>null</code>.
417      * @param destFile the file to copy to.
418      * Must not be <code>null</code>.
419      * @param filters the collection of filters to apply to this copy.
420      * @param overwrite Whether or not the destination file should be
421      * overwritten if it already exists.
422      * @param preserveLastModified Whether or not the last modified time of
423      * the resulting file should be set to that
424      * of the source file.
425      * @param encoding the encoding used to read and write the files.
426      *
427      * @throws IOException if the copying fails.
428      *
429      * @since Ant 1.5
430      */

431     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile,
432                          FilterSetCollection filters, boolean overwrite,
433                          boolean preserveLastModified, String JavaDoc encoding)
434         throws IOException JavaDoc {
435         copyFile(sourceFile, destFile, filters, null, overwrite,
436                  preserveLastModified, encoding, null);
437     }
438
439     /**
440      * Convenience method to copy a file from a source to a
441      * destination specifying if token filtering must be used, if
442      * filter chains must be used, if source files may overwrite
443      * newer destination files and the last modified time of
444      * <code>destFile</code> file should be made equal
445      * to the last modified time of <code>sourceFile</code>.
446      *
447      * @param sourceFile the file to copy from.
448      * Must not be <code>null</code>.
449      * @param destFile the file to copy to.
450      * Must not be <code>null</code>.
451      * @param filters the collection of filters to apply to this copy.
452      * @param filterChains filterChains to apply during the copy.
453      * @param overwrite Whether or not the destination file should be
454      * overwritten if it already exists.
455      * @param preserveLastModified Whether or not the last modified time of
456      * the resulting file should be set to that
457      * of the source file.
458      * @param encoding the encoding used to read and write the files.
459      * @param project the project instance.
460      *
461      * @throws IOException if the copying fails.
462      *
463      * @since Ant 1.5
464      */

465     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile,
466                          FilterSetCollection filters, Vector JavaDoc filterChains,
467                          boolean overwrite, boolean preserveLastModified,
468                          String JavaDoc encoding, Project project)
469         throws IOException JavaDoc {
470         copyFile(sourceFile, destFile, filters, filterChains,
471                  overwrite, preserveLastModified, encoding, encoding, project);
472     }
473
474     /**
475      * Convenience method to copy a file from a source to a
476      * destination specifying if token filtering must be used, if
477      * filter chains must be used, if source files may overwrite
478      * newer destination files and the last modified time of
479      * <code>destFile</code> file should be made equal
480      * to the last modified time of <code>sourceFile</code>.
481      *
482      * @param sourceFile the file to copy from.
483      * Must not be <code>null</code>.
484      * @param destFile the file to copy to.
485      * Must not be <code>null</code>.
486      * @param filters the collection of filters to apply to this copy.
487      * @param filterChains filterChains to apply during the copy.
488      * @param overwrite Whether or not the destination file should be
489      * overwritten if it already exists.
490      * @param preserveLastModified Whether or not the last modified time of
491      * the resulting file should be set to that
492      * of the source file.
493      * @param inputEncoding the encoding used to read the files.
494      * @param outputEncoding the encoding used to write the files.
495      * @param project the project instance.
496      *
497      *
498      * @throws IOException if the copying fails.
499      *
500      * @since Ant 1.6
501      */

502     public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile,
503                          FilterSetCollection filters, Vector JavaDoc filterChains,
504                          boolean overwrite, boolean preserveLastModified,
505                          String JavaDoc inputEncoding, String JavaDoc outputEncoding,
506                          Project project)
507         throws IOException JavaDoc {
508         ResourceUtils.copyResource(
509             new FileResource(sourceFile), new FileResource(destFile),
510             filters, filterChains, overwrite, preserveLastModified,
511             inputEncoding, outputEncoding, project);
512     }
513
514     // CheckStyle:ParameterNumberCheck ON
515

516     /**
517      * Calls File.setLastModified(long time). Originally written to
518      * to dynamically bind to that call on Java1.2+.
519      *
520      * @param file the file whose modified time is to be set
521      * @param time the time to which the last modified time is to be set.
522      * if this is -1, the current time is used.
523      */

524     public void setFileLastModified(File JavaDoc file, long time) {
525         ResourceUtils.setLastModified(new FileResource(file), time);
526     }
527
528     /**
529      * Interpret the filename as a file relative to the given file
530      * unless the filename already represents an absolute filename.
531      * Differs from <code>new File(file, filename)</code> in that
532      * the resulting File's path will always be a normalized,
533      * absolute pathname. Also, if it is determined that
534      * <code>filename</code> is context-relative, <code>file</code>
535      * will be discarded and the reference will be resolved using
536      * available context/state information about the filesystem.
537      *
538      * @param file the "reference" file for relative paths. This
539      * instance must be an absolute file and must not contain
540      * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
541      * of /). If it is null, this call is equivalent to
542      * <code>new java.io.File(filename).getAbsoluteFile()</code>.
543      *
544      * @param filename a file name.
545      *
546      * @return an absolute file.
547      * @throws java.lang.NullPointerException if filename is null.
548      */

549     public File JavaDoc resolveFile(File JavaDoc file, String JavaDoc filename) {
550         if (!isAbsolutePath(filename)) {
551             char sep = File.separatorChar;
552             filename = filename.replace('/', sep).replace('\\', sep);
553             if (isContextRelativePath(filename)) {
554                 file = null;
555                 // on cygwin, our current directory can be a UNC;
556
// assume user.dir is absolute or all hell breaks loose...
557
String JavaDoc udir = System.getProperty("user.dir");
558                 if (filename.charAt(0) == sep && udir.charAt(0) == sep) {
559                     filename = dissect(udir)[0] + filename.substring(1);
560                 }
561             }
562             filename = new File JavaDoc(file, filename).getAbsolutePath();
563         }
564         return normalize(filename);
565     }
566
567     /**
568      * On DOS and NetWare, the evaluation of certain file
569      * specifications is context-dependent. These are filenames
570      * beginning with a single separator (relative to current root directory)
571      * and filenames with a drive specification and no intervening separator
572      * (relative to current directory of the specified root).
573      * @param filename the filename to evaluate.
574      * @return true if the filename is relative to system context.
575      * @throws java.lang.NullPointerException if filename is null.
576      * @since Ant 1.7
577      */

578     public static boolean isContextRelativePath(String JavaDoc filename) {
579         if (!(onDos || onNetWare) || filename.length() == 0) {
580             return false;
581         }
582         char sep = File.separatorChar;
583         filename = filename.replace('/', sep).replace('\\', sep);
584         char c = filename.charAt(0);
585         int len = filename.length();
586         return (c == sep && (len == 1 || filename.charAt(1) != sep))
587             || (Character.isLetter(c) && len > 1
588             && filename.indexOf(':') == 1
589             && (len == 2 || filename.charAt(2) != sep));
590     }
591
592     /**
593      * Verifies that the specified filename represents an absolute path.
594      * Differs from new java.io.File("filename").isAbsolute() in that a path
595      * beginning with a double file separator--signifying a Windows UNC--must
596      * at minimum match "\\a\b" to be considered an absolute path.
597      * @param filename the filename to be checked.
598      * @return true if the filename represents an absolute path.
599      * @throws java.lang.NullPointerException if filename is null.
600      * @since Ant 1.6.3
601      */

602     public static boolean isAbsolutePath(String JavaDoc filename) {
603         int len = filename.length();
604         if (len == 0) {
605             return false;
606         }
607         char sep = File.separatorChar;
608         filename = filename.replace('/', sep).replace('\\', sep);
609         char c = filename.charAt(0);
610         if (!(onDos || onNetWare)) {
611             return (c == sep);
612         }
613         if (c == sep) {
614             if (!(onDos && len > 4 && filename.charAt(1) == sep)) {
615                 return false;
616             }
617             int nextsep = filename.indexOf(sep, 2);
618             return nextsep > 2 && nextsep + 1 < len;
619         }
620         int colon = filename.indexOf(':');
621         return (Character.isLetter(c) && colon == 1
622             && filename.length() > 2 && filename.charAt(2) == sep)
623             || (onNetWare && colon > 0);
624     }
625
626     /**
627      * Translate a path into its native (platform specific) format.
628      * <p>
629      * This method uses PathTokenizer to separate the input path
630      * into its components. This handles DOS style paths in a relatively
631      * sensible way. The file separators are then converted to their platform
632      * specific versions.
633      *
634      * @param toProcess The path to be translated.
635      * May be <code>null</code>.
636      *
637      * @return the native version of the specified path or
638      * an empty string if the path is <code>null</code> or empty.
639      *
640      * @since ant 1.7
641      * @see PathTokenizer
642      */

643     public static String JavaDoc translatePath(String JavaDoc toProcess) {
644         if (toProcess == null || toProcess.length() == 0) {
645             return "";
646         }
647         StringBuffer JavaDoc path = new StringBuffer JavaDoc(toProcess.length() + 50);
648         PathTokenizer tokenizer = new PathTokenizer(toProcess);
649         while (tokenizer.hasMoreTokens()) {
650             String JavaDoc pathComponent = tokenizer.nextToken();
651             pathComponent = pathComponent.replace('/', File.separatorChar);
652             pathComponent = pathComponent.replace('\\', File.separatorChar);
653             if (path.length() != 0) {
654                 path.append(File.pathSeparatorChar);
655             }
656             path.append(pathComponent);
657         }
658         return path.toString();
659     }
660
661     /**
662      * &quot;Normalize&quot; the given absolute path.
663      *
664      * <p>This includes:
665      * <ul>
666      * <li>Uppercase the drive letter if there is one.</li>
667      * <li>Remove redundant slashes after the drive spec.</li>
668      * <li>Resolve all ./, .\, ../ and ..\ sequences.</li>
669      * <li>DOS style paths that start with a drive letter will have
670      * \ as the separator.</li>
671      * </ul>
672      * Unlike {@link File#getCanonicalPath()} this method
673      * specifically does not resolve symbolic links.
674      *
675      * @param path the path to be normalized.
676      * @return the normalized version of the path.
677      *
678      * @throws java.lang.NullPointerException if path is null.
679      */

680     public File JavaDoc normalize(final String JavaDoc path) {
681         Stack JavaDoc s = new Stack JavaDoc();
682         String JavaDoc[] dissect = dissect(path);
683         s.push(dissect[0]);
684
685         StringTokenizer tok = new StringTokenizer(dissect[1], File.separator);
686         while (tok.hasMoreTokens()) {
687             String JavaDoc thisToken = tok.nextToken();
688             if (".".equals(thisToken)) {
689                 continue;
690             } else if ("..".equals(thisToken)) {
691                 if (s.size() < 2) {
692                     // Cannot resolve it, so skip it.
693
return new File JavaDoc(path);
694                 }
695                 s.pop();
696             } else { // plain component
697
s.push(thisToken);
698             }
699         }
700         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
701         for (int i = 0; i < s.size(); i++) {
702             if (i > 1) {
703                 // not before the filesystem root and not after it, since root
704
// already contains one
705
sb.append(File.separatorChar);
706             }
707             sb.append(s.elementAt(i));
708         }
709         return new File JavaDoc(sb.toString());
710     }
711
712     /**
713      * Dissect the specified absolute path.
714      * @param path the path to dissect.
715      * @return String[] {root, remaining path}.
716      * @throws java.lang.NullPointerException if path is null.
717      * @since Ant 1.7
718      */

719     public String JavaDoc[] dissect(String JavaDoc path) {
720         char sep = File.separatorChar;
721         path = path.replace('/', sep).replace('\\', sep);
722
723         // make sure we are dealing with an absolute path
724
if (!isAbsolutePath(path)) {
725             throw new BuildException(path + " is not an absolute path");
726         }
727         String JavaDoc root = null;
728         int colon = path.indexOf(':');
729         if (colon > 0 && (onDos || onNetWare)) {
730
731             int next = colon + 1;
732             root = path.substring(0, next);
733             char[] ca = path.toCharArray();
734             root += sep;
735             //remove the initial separator; the root has it.
736
next = (ca[next] == sep) ? next + 1 : next;
737
738             StringBuffer JavaDoc sbPath = new StringBuffer JavaDoc();
739             // Eliminate consecutive slashes after the drive spec:
740
for (int i = next; i < ca.length; i++) {
741                 if (ca[i] != sep || ca[i - 1] != sep) {
742                     sbPath.append(ca[i]);
743                 }
744             }
745             path = sbPath.toString();
746         } else if (path.length() > 1 && path.charAt(1) == sep) {
747             // UNC drive
748
int nextsep = path.indexOf(sep, 2);
749             nextsep = path.indexOf(sep, nextsep + 1);
750             root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
751             path = path.substring(root.length());
752         } else {
753             root = File.separator;
754             path = path.substring(1);
755         }
756         return new String JavaDoc[] {root, path};
757     }
758
759     /**
760      * Returns a VMS String representation of a <code>File</code> object.
761      * This is useful since the JVM by default internally converts VMS paths
762      * to Unix style.
763      * The returned String is always an absolute path.
764      *
765      * @param f The <code>File</code> to get the VMS path for.
766      * @return The absolute VMS path to <code>f</code>.
767      */

768     public String JavaDoc toVMSPath(File JavaDoc f) {
769         // format: "DEVICE:[DIR.SUBDIR]FILE"
770
String JavaDoc osPath;
771         String JavaDoc path = normalize(f.getAbsolutePath()).getPath();
772         String JavaDoc name = f.getName();
773         boolean isAbsolute = path.charAt(0) == File.separatorChar;
774         // treat directories specified using .DIR syntax as files
775
boolean isDirectory = f.isDirectory()
776             && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
777
778         String JavaDoc device = null;
779         StringBuffer JavaDoc directory = null;
780         String JavaDoc file = null;
781
782         int index =