001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.tools.file;
031:
032: import java.io.File;
033: import java.io.IOException;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.List;
037:
038: /**
039: * this class provides functions used to generate a relative path from two
040: * absolute paths
041: */
042: public class RelativePath {
043: protected RelativePath() {
044: //
045: }
046:
047: /**
048: * get relative path of File 'f' with respect to 'home' directory example :
049: * home = /a/b/c f = /a/d/e/x.txt s = getRelativePath(home,f) =
050: * ../../d/e/x.txt
051: *
052: * @param home
053: * base path, should be a directory, not a file, or it doesn't
054: * make sense
055: * @param f
056: * file to generate path for
057: *
058: * @return path from home to f as a string
059: */
060: public static String getRelativePath(File source, File target)
061: throws IOException {
062: String relativePath = null;
063: if (source != null) {
064: List sourceList = getPathList(source);
065: List targetList = getPathList(target);
066: relativePath = matchPathLists(sourceList, targetList);
067: }
068: if (relativePath == null) {
069: return target.getAbsolutePath();
070: } else {
071: return relativePath;
072: }
073: }
074:
075: /**
076: * break a path down into individual elements and add to a list. example :
077: * if a path is /a/b/c/d.txt, the breakdown will be [d.txt,c,b,a]
078: *
079: * @param f
080: * input file
081: *
082: * @return a List collection with the individual elements of the path in
083: * reverse order
084: */
085: private static List getPathList(File f) throws IOException {
086: List l = new ArrayList();
087: File r = f.getCanonicalFile();
088: while (r != null) {
089: if (r.getName().length() == 0) {
090: int dblptIndex = r.getPath().indexOf(":");
091: if (dblptIndex == -1) {
092: l.add("");
093: } else {
094: l.add(r.getPath().substring(0, dblptIndex));
095: }
096: } else {
097: l.add(r.getName());
098: }
099: r = r.getParentFile();
100: }
101:
102: List reversed = new ArrayList();
103: for (int i = l.size() - 1; i >= 0; i--) {
104: reversed.add(l.get(i));
105: }
106: return reversed;
107: }
108:
109: /**
110: * figure out a string representing the relative path of 'f' with respect to
111: * 'r'
112: *
113: * @param r
114: * home path
115: * @param f
116: * path of file
117: *
118: * @return docme
119: */
120: private static String matchPathLists(List source, List target) {
121: Iterator sourceIterator = source.iterator();
122: Iterator targetIterator = target.iterator();
123:
124: // remove equal path components
125: boolean intersection = false;
126: while (sourceIterator.hasNext() && targetIterator.hasNext()) {
127: if (sourceIterator.next().equals(targetIterator.next())) {
128: sourceIterator.remove();
129: targetIterator.remove();
130: intersection = true;
131: } else {
132: break;
133: }
134: }
135:
136: // only the differing path components remain
137: if (!intersection) {
138: return null;
139: }
140: String relPath = "";
141: for (int i = 0; i < source.size(); i++) {
142: relPath += (".." + File.separator);
143: }
144: for (Iterator i = target.iterator(); i.hasNext();) {
145: relPath += (i.next());
146: if (i.hasNext()) {
147: relPath += File.separator;
148: }
149: }
150: return relPath;
151: }
152: }
|