package de.haukerehfeld.quakeinjector;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* this class provides functions used to generate a relative path
* from two absolute paths
* @see http://www.devx.com/tips/Tip/13737
*/
public class RelativePath {
/**
* break a path down into individual elements and add to a list.
* example : if a path is /a/b/c/d.txt, the breakdown will be [d.txt,c,b,a]
* @param f input file
* @return a List collection with the individual elements of the path in
reverse order
*/
private static List<File> getPathList(File f) {
List<File> list = new ArrayList<File>();
File parent;
try {
parent = f.getCanonicalFile();
while (parent != null) {
list.add(parent);
parent = parent.getParentFile();
}
}
catch (IOException e) {
e.printStackTrace();
list = null;
}
return list;
}
private static int getFirstRootPosition(List<File> file) {
File[] roots = File.listRoots();
for (File root: roots) {
// System.out.println("Root: " + root);
}
int i = 0;
done: while (i < file.size() - 1) {
for (File root: roots) {
if (file.get(i).equals(root)) {
break done;
}
// System.out.println(root + " isn't " + file.get(i));
}
i++;
}
// System.out.println("Root is " + file.get(i));
return i;
}
/**
* figure out a string representing the relative path of
* 'f' with respect to 'r'
* @param home home path list
* @param file path of file list
*/
private static File matchPathLists(List<File> home, List<File> file) {
if (file.size() <= 0) {
return new File("");
}
if (home.size() <= 0) {
return file.get(0);
}
// start at the beginning of the lists
// iterate while both lists are equal
final int homeLast = home.size() - 1;
final int fileLast = file.size() - 1;
int i = getFirstRootPosition(home);
int j = getFirstRootPosition(file);
//the root isn't identical (common on win32) - just return an absolute path
if (!home.get(i).equals(file.get(j))) {
// System.out.println(home);
// System.out.println(file);
// System.out.println(home.get(i) + " != " + file.get(j));
return file.get(0);
}
// first eliminate common root
while((i >= 0) && (j >= 0) && (home.get(i).equals(file.get(j)))) {
i--;
j--;
}
StringBuilder result = new StringBuilder();
// for each remaining level in the home path, add a ..
for(; i >= 0; i--) {
result.append(".." + File.separator);
}
// for each level in the file path, add the path
for(; j >= 1; j--) {
result.append(file.get(j).getName() + File.separator);
}
if (j >= 0) {
// file name doesn't need separator at the end
result.append(file.get(j).getName());
}
return new File(result.toString());
}
/**
* get relative path of File 'f' with respect to 'home' directory
* example : home = /a/b/c
* f = /a/d/e/x.txt
* s = getRelativePath(home,f) = ../../d/e/x.txt
* @param home base path, should be a directory, not a file, or it doesn't
make sense
* @param file file to generate path for
* @return path from home to f as a string
*/
public static File getRelativePath(File home, File file){
List<File> homelist;
List<File> filelist;
//System.out.println("home: " + home);
//System.out.println("file: " + file);
homelist = getPathList(home);
filelist = getPathList(file);
File result = matchPathLists(homelist,filelist);
//System.out.println("getName(): " + result.getName());
//System.out.println("getToString(): " + result.toString());
return result;
}
}