2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.util;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
27 * utility class to find all files matching (possibly hierarchical)
30 * we support single '*' wildcards as in filename matching, plus "**" patterns
31 * that match all (recursive) subdirectories
33 // example: List<File> list = findMatches("/U*/p*/tmp/**/*.java");
35 public class FileUtils {
37 public static boolean containsWildcards (String pattern) {
38 return (pattern.indexOf('*') >= 0);
41 //--- processing wildcard path specs
43 public static String[] expandWildcards (String[] pathNames){
44 ArrayList<String> list = null;
46 if (pathNames == null){
50 for (int i=0; i<pathNames.length; i++){
51 String e = pathNames[i];
53 if (containsWildcards(e)){
55 list= new ArrayList<String>(pathNames.length + 20);
56 for (int j=0; j<i; j++){
57 list.add(pathNames[j]);
61 for (File f : findMatches(e)){
62 list.add(f.getAbsolutePath());
73 return list.toArray(new String[list.size()]);
80 private static List<File> splitPath (String pattern) {
81 ArrayList<File> list = new ArrayList<File>();
83 for (File f = new File(pattern); f != null; f = f.getParentFile()) {
87 Collections.reverse(list);
91 private static void addSubdirs (List<File> list, File dir){
92 for (File f : dir.listFiles()) {
100 private static List<File> findMatches (File dir, String pattern) {
101 ArrayList<File> list = new ArrayList<File>();
103 if (dir.isDirectory()) {
104 if ("**".equals(pattern)) { // recursively add all subdirectories
105 addSubdirs(list, dir);
108 StringMatcher sm = new StringMatcher(pattern);
109 for (File f : dir.listFiles()) {
110 if (sm.matches(f.getName())) {
120 public static List<File> findMatches (String pattern) {
121 List<File> pathComponents = splitPath(pattern);
122 List<File> matches = null;
124 for (File f : pathComponents) {
125 String fname = f.getName();
126 if (matches == null) { // first one
127 if (fname.isEmpty()) { // filesystem root
128 matches = new ArrayList<File>();
131 matches = findMatches(new File(System.getProperty("user.dir")), fname);
135 List<File> newMatches = new ArrayList<File>();
136 for (File d : matches) {
137 newMatches.addAll(findMatches(d, fname));
139 matches = newMatches;
142 if (matches.isEmpty()) {
152 public static URL getURL (String spec){
154 // check if there is a protocol specification
155 if (spec.indexOf("://") >= 0) {
156 return new URL(spec);
159 File f = new File(spec).getCanonicalFile();
160 return f.toURI().toURL();
162 } catch (Throwable x) {
163 throw new RuntimeException("illegal pathname: " + spec);
167 public static URL[] getURLs (String[] paths){
168 ArrayList<URL> urls = new ArrayList<URL>();
170 for (String p : paths) {
171 urls.add( getURL(p));
174 return urls.toArray(new URL[urls.size()]);
177 public static URL[] getURLs (List<String> paths){
178 ArrayList<URL> urls = new ArrayList<URL>();
180 for (String p : paths) {
181 urls.add( getURL(p));
184 return urls.toArray(new URL[urls.size()]);
188 //--- platform specific path conversion
191 * turn a mixed path list into a valid Unix path set without drive letters,
192 * and with '/' and ':' separators. Also remove multiple consecutive separators
193 * this assumes the path String to be already expanded
195 public static String asCanonicalUnixPath (String p) {
196 boolean changed = false;
199 char[] buf = new char[n];
200 p.getChars(0, n, buf, 0);
202 for (int i=0; i<n; i++) {
204 if (c == '/' || c == '\\') {
206 buf[i] = '/'; changed = true;
209 // remove multiple occurrences of dir separators
212 for (c = buf[i1]; i1 < n && (c == '/' || c == '\\'); c = buf[i1]) {
213 System.arraycopy(buf, i + 2, buf, i1, n - (i + 2));
219 } else if (c == ':') {
220 // strip drive letters - maybe this is trying to be too smart,
221 // since we only do this for a "...:X:\..." but not a
222 // "...:X:/...", which could be a valid unix path list
224 // is this part of a drive letter spec?
227 if (buf[i1] == '\\') {
229 if (i == 1 || (buf[i-2] == ':')){ // strip the drive letter
230 System.arraycopy(buf, i1, buf, i-1, n - (i1));
238 } else if (c == ';'){
239 buf[i] = ':'; changed = true;
241 } else if (c == ',') {
242 buf[i] = ':'; changed = true;
245 if (buf[i] == ':') { // remove multiple occurrences of path separators
248 for (c = buf[i1] ;(c == ':' || c == ';' || c == ','); c = buf[i1]){
249 System.arraycopy(buf, i+2, buf, i1, n - (i+2));
258 p = new String(buf, 0, n);
265 * turn a mixed path list into a valid Windows path set with drive letters,
266 * and '\' and ';' separators. Also remove multiple consecutive separators
267 * this assumes the path String to be already expanded
269 public static String asCanonicalWindowsPath (String p) {
270 boolean changed = false;
273 char[] buf = new char[n];
274 p.getChars(0, n, buf, 0);
276 for (int i=0; i<n; i++) {
278 if (c == '/' || c == '\\') {
280 buf[i] = '\\'; changed = true;
283 // remove multiple occurrences of dir separators
286 for (c = buf[i1]; i1 < n && (c == '/' || c == '\\'); c = buf[i1]) {
287 System.arraycopy(buf, i + 2, buf, i1, n - (i + 2));
293 } else if (c == ':') {
294 // is this part of a drive letter spec?
296 if (i1<n && (buf[i1] == '\\' || buf[i1] == '/')) {
298 if (i == 1 || (buf[i-2] == ';')){
303 buf[i] = ';'; changed = true;
305 } else if (c == ',') {
306 buf[i] = ';'; changed = true;
309 if (buf[i] == ';') { // remove multiple occurrences of path separators
312 for (c = buf[i1] ;(c == ':' || c == ';' || c == ','); c = buf[i1]){
313 System.arraycopy(buf, i+2, buf, i1, n - (i+2));
322 p = new String(buf, 0, n);
329 public static String asPlatformPath (String p) {
330 if (File.separatorChar == '/') { // Unix'ish file system
331 p = asCanonicalUnixPath(p);
332 } else { // Windows'ish file system
333 p = asCanonicalWindowsPath(p);
339 public static void printFile (PrintWriter pw, File file){
341 FileReader fr = new FileReader(file);
342 BufferedReader r = new BufferedReader(fr);
345 while ((line = r.readLine()) != null){
351 } catch (IOException iox){
352 pw.println("!! error printing file: " + file.getPath());
356 public static boolean removeRecursively(File file) {
358 File[] childs = file.listFiles();
360 for (File child : childs) {
361 if (child.isDirectory()){
362 removeRecursively(child);
368 return file.delete();
374 public static byte[] getContents( File file) throws IOException {
376 long length = file.length();
377 byte[] data = new byte[(int)length];
379 FileInputStream is = new FileInputStream(file);
381 getContents(is, data);
383 } catch (IOException iox){
396 public static void getContents(InputStream is, byte[] buf) throws IOException {
398 while (nRead < buf.length) {
399 int n = is.read(buf, nRead, buf.length - nRead);
401 throw new IOException("premature end of inputstream: " + buf.length + '/' + nRead);
407 public static String getContentsAsString( File file) throws IOException {
408 byte[] data = getContents(file);
409 return new String(data);
412 public static void setContents(File file, byte[] data) throws IOException {
413 FileOutputStream os = new FileOutputStream(file);
418 public static void setContents(File file, String data) throws IOException {
419 FileWriter fw = new FileWriter(file);
424 public static String asCanonicalUserPathName (String path){
425 String userHome = System.getProperty("user.home");
426 int len = userHome.length();
427 if (path.startsWith(userHome) && path.charAt(len) == '/') {
428 return "${user.home}" + path.substring(len).replace('\\', '/');
430 return path.replace('\\', '/');
434 public static String asUnixPathName (File file){
435 String userHome = System.getProperty("user.home") + File.separatorChar;
436 int uhLen = userHome.length();
438 String pn = file.getAbsolutePath();
439 if (pn.startsWith(userHome)) {
440 pn = "~/" + pn.substring(uhLen).replace('\\', '/');
442 pn = pn.replace('\\', '/');
447 public static String unixToUserPathName (String unixPathName){
448 if (unixPathName.startsWith("~/")){
449 return "${user.home}" + unixPathName.substring(1);
451 String userHome = System.getProperty("user.home");
452 int len = userHome.length();
453 if (unixPathName.startsWith(userHome) && unixPathName.charAt(len) == '/'){
454 return "${user.home}" + unixPathName.substring(len);
461 public static boolean ensureDirs (File file){
462 File dir = file.getParentFile();
463 if (!dir.isDirectory()){
470 public static String getRelativeUnixPath (File baseDir, File refFile) throws IOException {
471 String bpn = baseDir.getCanonicalPath().replace('\\', '/');
472 String rpn = refFile.getCanonicalPath().replace('\\', '/');
474 int len = Math.min(bpn.length(), rpn.length());
475 for (int i = 0, n = 0; i < len; i++) {
476 char c = bpn.charAt(i);
479 } else if (c != rpn.charAt(i)) {
480 bpn = bpn.substring(n);
481 rpn = rpn.substring(n);
488 for (int i = 0; i < len; i++) {
489 if (bpn.charAt(i) == '/') {
494 String relPath = up + rpn;
498 public static boolean copyFile (File src, File toDir) throws IOException {
500 File tgt = new File(toDir, src.getName());
501 if (tgt.createNewFile()) {
502 byte[] data = getContents(src);
503 setContents(tgt, data);