//
// Copyright (C) 2010 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* utility class to find all files matching (possibly hierarchical)
* wildcard path specs
*
* we support single '*' wildcards as in filename matching, plus "**" patterns
* that match all (recursive) subdirectories
*/
// example: List<File> list = findMatches("/U*/p*/tmp/**/*.java");
public class FileUtils {
public static boolean containsWildcards (String pattern) {
return (pattern.indexOf('*') >= 0);
}
//--- processing wildcard path specs
public static String[] expandWildcards (String[] pathNames){
ArrayList<String> list = null;
if (pathNames == null){
return new String[0];
}
for (int i=0; i<pathNames.length; i++){
String e = pathNames[i];
if (containsWildcards(e)){
if (list == null){
list= new ArrayList<String>(pathNames.length + 20);
for (int j=0; j<i; j++){
list.add(pathNames[j]);
}
}
for (File f : findMatches(e)){
list.add(f.getAbsolutePath());
}
} else {
if (list != null){
list.add(e);
}
}
}
if (list != null){
return list.toArray(new String[list.size()]);
} else {
return pathNames;
}
}
private static List<File> splitPath (String pattern) {
ArrayList<File> list = new ArrayList<File>();
for (File f = new File(pattern); f != null; f = f.getParentFile()) {
list.add(f);
}
Collections.reverse(list);
return list;
}
private static void addSubdirs (List<File> list, File dir){
for (File f : dir.listFiles()) {
if (f.isDirectory()){
list.add(f);
addSubdirs(list, f);
}
}
}
private static List<File> findMatches (File dir, String pattern) {
ArrayList<File> list = new ArrayList<File>();
if (dir.isDirectory()) {
if ("**".equals(pattern)) { // recursively add all subdirectories
addSubdirs(list, dir);
} else {
StringMatcher sm = new StringMatcher(pattern);
for (File f : dir.listFiles()) {
if (sm.matches(f.getName())) {
list.add(f);
}
}
}
}
return list;
}
public static List<File> findMatches (String pattern) {
List<File> pathComponents = splitPath(pattern);
List<File> matches = null;
for (File f : pathComponents) {
String fname = f.getName();
if (matches == null) { // first one
if (fname.isEmpty()) { // filesystem root
matches = new ArrayList<File>();
matches.add(f);
} else {
matches = findMatches(new File(System.getProperty("user.dir")), fname);
}
} else {
List<File> newMatches = new ArrayList<File>();
for (File d : matches) {
newMatches.addAll(findMatches(d, fname));
}
matches = newMatches;
}
if (matches.isEmpty()) {
return matches;
}
}
return matches;
}
//--- URL conversion
public static URL getURL (String spec){
try {
// check if there is a protocol specification
if (spec.indexOf("://") >= 0) {
return new URL(spec);
} else {
File f = new File(spec).getCanonicalFile();
return f.toURI().toURL();
}
} catch (Throwable x) {
throw new RuntimeException("illegal pathname: " + spec);
}
}
public static URL[] getURLs (String[] paths){
ArrayList<URL> urls = new ArrayList<URL>();
for (String p : paths) {
urls.add( getURL(p));
}
return urls.toArray(new URL[urls.size()]);
}
public static URL[] getURLs (List<String> paths){
ArrayList<URL> urls = new ArrayList<URL>();
for (String p : paths) {
urls.add( getURL(p));
}
return urls.toArray(new URL[urls.size()]);
}
//--- platform specific path conversion
/**
* turn a mixed path list into a valid Unix path set without drive letters,
* and with '/' and ':' separators. Also remove multiple consecutive separators
* this assumes the path String to be already expanded
*/
public static String asCanonicalUnixPath (String p) {
boolean changed = false;
int n = p.length();
char[] buf = new char[n];
p.getChars(0, n, buf, 0);
for (int i=0; i<n; i++) {
char c = buf[i];
if (c == '/' || c == '\\') {
if (c == '\\'){
buf[i] = '/'; changed = true;
}
// remove multiple occurrences of dir separators
int i1 = i+1;
if (i1 < n){
for (c = buf[i1]; i1 < n && (c == '/' || c == '\\'); c = buf[i1]) {
System.arraycopy(buf, i + 2, buf, i1, n - (i + 2));
n--;
changed = true;
}
}
} else if (c == ':') {
// strip drive letters - maybe this is trying to be too smart,
// since we only do this for a "...:X:\..." but not a
// "...:X:/...", which could be a valid unix path list
// is this part of a drive letter spec?
int i1 = i+1;
if (i1<n) {
if (buf[i1] == '\\') {
if (i>0) {
if (i == 1 || (buf[i-2] == ':')){ // strip the drive letter
System.arraycopy(buf, i1, buf, i-1, n - (i1));
n-=2;
changed = true;
}
}
}
}
} else if (c == ';'){
buf[i] = ':'; changed = true;
} else if (c == ',') {
buf[i] = ':'; changed = true;
}
if (buf[i] == ':') { // remove multiple occurrences of path separators
int i1 = i+1;
if (i1<n) {
for (c = buf[i1] ;(c == ':' || c == ';' || c == ','); c = buf[i1]){
System.arraycopy(buf, i+2, buf, i1, n - (i+2));
n--;
changed = true;
}
}
}
}
if (changed) {
p = new String(buf, 0, n);
}
return p;
}
/**
* turn a mixed path list into a valid Windows path set with drive letters,
* and '\' and ';' separators. Also remove multiple consecutive separators
* this assumes the path String to be already expanded
*/
public static String asCanonicalWindowsPath (String p) {
boolean changed = false;
int n = p.length();
char[] buf = new char[n];
p.getChars(0, n, buf, 0);
for (int i=0; i<n; i++) {
char c = buf[i];
if (c == '/' || c == '\\') {
if (c == '/'){
buf[i] = '\\'; changed = true;
}
// remove multiple occurrences of dir separators
int i1 = i+1;
if (i1 < n) {
for (c = buf[i1]; i1 < n && (c == '/' || c == '\\'); c = buf[i1]) {
System.arraycopy(buf, i + 2, buf, i1, n - (i + 2));
n--;
changed = true;
}
}
} else if (c == ':') {
// is this part of a drive letter spec?
int i1 = i+1;
if (i1<n && (buf[i1] == '\\' || buf[i1] == '/')) {
if (i>0) {
if (i == 1 || (buf[i-2] == ';')){
continue;
}
}
}
buf[i] = ';'; changed = true;
} else if (c == ',') {
buf[i] = ';'; changed = true;
}
if (buf[i] == ';') { // remove multiple occurrences of path separators
int i1 = i+1;
if (i1<n) {
for (c = buf[i1] ;(c == ':' || c == ';' || c == ','); c = buf[i1]){
System.arraycopy(buf, i+2, buf, i1, n - (i+2));
n--;
changed = true;
}
}
}
}
if (changed) {
p = new String(buf, 0, n);
}
return p;
}
public static String asPlatformPath (String p) {
if (File.separatorChar == '/') { // Unix'ish file system
p = asCanonicalUnixPath(p);
} else { // Windows'ish file system
p = asCanonicalWindowsPath(p);
}
return p;
}
public static void printFile (PrintWriter pw, File file){
try {
FileReader fr = new FileReader(file);
BufferedReader r = new BufferedReader(fr);
String line;
while ((line = r.readLine()) != null){
pw.println(line);
}
r.close();
} catch (IOException iox){
pw.println("!! error printing file: " + file.getPath());
}
}
public static boolean removeRecursively(File file) {
if (file.exists()) {
File[] childs = file.listFiles();
for (File child : childs) {
if (child.isDirectory()){
removeRecursively(child);
} else {
child.delete();
}
}
return file.delete();
}
return false;
}
public static byte[] getContents( File file) throws IOException {
if (file.isFile()){
long length = file.length();
byte[] data = new byte[(int)length];
FileInputStream is = new FileInputStream(file);
try {
getContents(is, data);
} catch (IOException iox){
return null;
} finally {
is.close();
}
return data;
}
return null;
}
public static void getContents(InputStream is, byte[] buf) throws IOException {
int nRead = 0;
while (nRead < buf.length) {
int n = is.read(buf, nRead, buf.length - nRead);
if (n < 0) {
throw new IOException("premature end of inputstream: " + buf.length + '/' + nRead);
}
nRead += n;
}
}
public static String getContentsAsString( File file) throws IOException {
byte[] data = getContents(file);
return new String(data);
}
public static void setContents(File file, byte[] data) throws IOException {
FileOutputStream os = new FileOutputStream(file);
os.write(data);
os.close();
}
public static void setContents(File file, String data) throws IOException {
FileWriter fw = new FileWriter(file);
fw.append(data);
fw.close();
}
public static String asCanonicalUserPathName (String path){
String userHome = System.getProperty("user.home");
int len = userHome.length();
if (path.startsWith(userHome) && path.charAt(len) == '/') {
return "${user.home}" + path.substring(len).replace('\\', '/');
} else {
return path.replace('\\', '/');
}
}
public static String asUnixPathName (File file){
String userHome = System.getProperty("user.home") + File.separatorChar;
int uhLen = userHome.length();
String pn = file.getAbsolutePath();
if (pn.startsWith(userHome)) {
pn = "~/" + pn.substring(uhLen).replace('\\', '/');
} else {
pn = pn.replace('\\', '/');
}
return pn;
}
public static String unixToUserPathName (String unixPathName){
if (unixPathName.startsWith("~/")){
return "${user.home}" + unixPathName.substring(1);
} else {
String userHome = System.getProperty("user.home");
int len = userHome.length();
if (unixPathName.startsWith(userHome) && unixPathName.charAt(len) == '/'){
return "${user.home}" + unixPathName.substring(len);
} else {
return unixPathName;
}
}
}
public static boolean ensureDirs (File file){
File dir = file.getParentFile();
if (!dir.isDirectory()){
return dir.mkdirs();
} else {
return true;
}
}
public static String getRelativeUnixPath (File baseDir, File refFile) throws IOException {
String bpn = baseDir.getCanonicalPath().replace('\\', '/');
String rpn = refFile.getCanonicalPath().replace('\\', '/');
int len = Math.min(bpn.length(), rpn.length());
for (int i = 0, n = 0; i < len; i++) {
char c = bpn.charAt(i);
if (c == '/') {
n = i + 1;
} else if (c != rpn.charAt(i)) {
bpn = bpn.substring(n);
rpn = rpn.substring(n);
break;
}
}
len = bpn.length();
String up = "";
for (int i = 0; i < len; i++) {
if (bpn.charAt(i) == '/') {
up += "../";
}
}
String relPath = up + rpn;
return relPath;
}
public static boolean copyFile (File src, File toDir) throws IOException {
if (src.isFile()) {
File tgt = new File(toDir, src.getName());
if (tgt.createNewFile()) {
byte[] data = getContents(src);
setContents(tgt, data);
return true;
}
}
return false;
}
}