/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.mbl.jif.imaging.nav.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FilenameUtils;
/**
*
* @author GBH
*/
public class FilePathUtils {
public static final String SHORTENER_ELLIPSE = "...";
/**
* Compacts a path into a given number of characters. The result is similar to the Win32 API
* PathCompactPathExA.
*
* @param path the path to the file (relative or absolute)
* @param limit the number of characters to which the path should be limited
* @return shortened path
*/
public static String limitPath(final String path, final int limit) {
if (path.length() <= limit) {
return path;
}
final char shortPathArray[] = new char[limit];
final char pathArray[] = path.toCharArray();
final char ellipseArray[] = SHORTENER_ELLIPSE.toCharArray();
final int pathindex = pathArray.length - 1;
final int shortpathindex = limit - 1;
// fill the array from the end
int i = 0;
for (; i < limit; i++) {
if (pathArray[pathindex - i] != '/' && pathArray[pathindex - i] != '\\') {
shortPathArray[shortpathindex - i] = pathArray[pathindex - i];
} else {
break;
}
}
// check how much space is left
final int free = limit - i;
if (free < SHORTENER_ELLIPSE.length()) {
// fill the beginning with ellipse
for (int j = 0; j < ellipseArray.length; j++) {
shortPathArray[j] = ellipseArray[j];
}
} else {
// fill the beginning with path and leave room for the ellipse
int j = 0;
for (; j + ellipseArray.length < free; j++) {
shortPathArray[j] = pathArray[j];
}
// ... add the ellipse
for (int k = 0; j + k < free; k++) {
shortPathArray[j + k] = ellipseArray[k];
}
}
return new String(shortPathArray);
}
public static String forceForwardSlashes(String dirPath) {
String foreslash = "/";
String regex = "\\\\";
final String dirPathFixed = dirPath.replaceAll(regex, foreslash);
return dirPathFixed;
}
public static String getRelativePath(String containingPath, String pathOfFile)
throws IllegalArgumentException {
String filePath = FilePathUtils.forceForwardSlashes(pathOfFile);
// Why? to deal with case of "/C:..."
if (filePath.startsWith("/")) {
filePath = filePath.substring(1, filePath.length());
}
String dirPath = FilePathUtils.forceForwardSlashes(containingPath);
String commonPath = commonPath(new String[]{dirPath, filePath});
// DEBUG
//System.out.println("commonPath: " + commonPath);
//System.out.println("filePath: " + filePath);
//
String relativePath = relativize(commonPath, filePath);
return relativePath;
}
private static String commonPath(String... paths) {
String commonPath = "";
String[][] folders = new String[paths.length][];
for (int i = 0; i < paths.length; i++) {
folders[i] = paths[i].split("/");
}
for (int j = 0; j < folders[0].length; j++) {
String thisFolder = folders[0][j];
boolean allMatched = true; //assume all have matched in case there are no more paths
for (int i = 1; i < folders.length && allMatched; i++) {
if (folders[i].length < j) {
allMatched = false;
break; //stop looking because we've gone as far as we can
}
allMatched &= folders[i][j].equals(thisFolder);
}
if (allMatched) {
commonPath += thisFolder + "/";
} else {
//otherwise
break; //stop looking
}
}
return commonPath;
}
/**
* Calculates the relative path between a specified root directory and a target path.
*
* @param root The absolute path of the root directory.
* @param target The path to the target file or directory.
* @return The relative path between the specified root directory and the target path.
* @throws IllegalArgumentException <ul><li>The root file cannot be null.</li><li>The target
* cannot be null.</li><li>The root file must be a directory.</li><li>The root file must be
* absolute.</li></ul>
*/
private static String relativize(final String root, final String target)
throws IllegalArgumentException {
return relativize(new File(root), new File(target));
}
private static String relativize(final File root, final File target)
throws IllegalArgumentException {
if (root == null) {
throw new IllegalArgumentException("The root file cannot be null.");
}
if (target == null) {
throw new IllegalArgumentException("The target cannot be null.");
}
if (!root.isDirectory()) {
throw new IllegalArgumentException("The root file must be a directory: " + root);
}
if (!root.isAbsolute()) {
throw new IllegalArgumentException("The root file must be absolute: " + root);
}
if (!target.isAbsolute()) {
return target.toString();
}
if (root.equals(target)) {
return ".";
}
final Deque<File> rootHierarchy = new ArrayDeque<File>();
for (File f = root; f != null; f = f.getParentFile()) {
rootHierarchy.push(f);
}
final Deque<File> targetHierarchy = new ArrayDeque<File>();
for (File f = target; f != null; f = f.getParentFile()) {
targetHierarchy.push(f);
}
while (rootHierarchy.size() > 0 && targetHierarchy.size() > 0 && rootHierarchy.peek().equals(
targetHierarchy.peek())) {
rootHierarchy.pop();
targetHierarchy.pop();
}
final StringBuilder sb = new StringBuilder(rootHierarchy.size() * 3 + targetHierarchy.size()
* 32);
while (rootHierarchy.size() > 0) {
sb.append("..");
rootHierarchy.pop();
if (rootHierarchy.size() > 0 || targetHierarchy.size() > 0) {
sb.append("/");
}
}
while (targetHierarchy.size() > 0) {
sb.append(targetHierarchy.pop().getName());
if (targetHierarchy.size() > 0) {
sb.append("/");
}
}
return sb.toString();
}
// ================================================
public static void main(String[] args) {
//String root = "C:\\MicroManagerData\\Test";
String root = "C:/MicroManagerData/Test";
String target = "C:\\MicroManagerData\\Test\\dataXMT16_1\\dataXMT16_MMImages_Pos0.ome.tif";
//String target = "MicroManagerData/Test/dataXMT16_1/dataXMT16_MMImages_Pos0.ome.tif";
test(root, target);
root = "C:\\Program Files\\Program Files\\PROJECT1PROJECT1";
target = "C:\\Program Files\\PROJECT1";
// "Program Files\\PROJECT1\\PROJECT1.cfg";
test(root, target);
root = "C:\\Windows\\Local Settings\\Application Data\\PROJECT1";
target = "C:\\Windows\\Local Settings\\Application Data\\PROJECT1\\PROJECT1.cfg";
test(root, target);
root = "/etc";
target = "/etc/project1.cfg";
test(root, target);
root = "/Users/user/.config/project1";
target = "/Users/user/.config/project1/project1.cfg";
test(root, target);
}
public static void test(String root, String target) {
try {
System.out.println("" + root + "\n" + target);
System.out.println("normalized: " + FilenameUtils.normalize(root));
File f = new File(root);
System.out.println("canonical: " + f.getCanonicalPath());
System.out.println("absolute: " + f.getAbsolutePath());
Path p = f.toPath();
System.out.println("path: " + p.toString());
if (f.isDirectory()) {
String result = FilePathUtils.getRelativePath(root, target);
System.out.println("relative: " + result);
} else {
System.out.println("root not a directory");
}
// String rootFixed = FilePathUtils.forceForwardSlashes(root);
// String targetFixed = FilePathUtils.forceForwardSlashes(target);
// System.out.println("commonPath: " + FilePathUtils.commonPath(new String[]{rootFixed, targetFixed}));
// System.out.println("limitPath: " + limitPath(target, 55));
// System.out.println("limitPath(/): " + limitPath(targetFixed, 55));
System.out.println("");
} catch (Exception ex) {
Logger.getLogger(FilePathUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
}