package com.github.sommeri.less4j.utils; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.regex.Pattern; import org.apache.commons.io.FilenameUtils; import com.github.sommeri.less4j.LessSource; import com.github.sommeri.less4j.LessSource.FileSource; import com.github.sommeri.less4j.platform.Constants; public class URIUtils { public static final String URI_FILE_SEPARATOR = "/"; public static URL toParentURL(URL url) { URL parentUrl; try { // compute parent URL URL rootParentUrl = new URL(url, ""); // add query string to parent URL String query = url.getQuery(); if (query == null || query.isEmpty()) { parentUrl = new URL(rootParentUrl.toString()); } else { parentUrl = new URL(rootParentUrl.toString() + query); } } catch (MalformedURLException ex) { throw new RuntimeException(ex); } return parentUrl; } public static String relativize(File from, File to) { URI fromURI = from.toURI(); URI toURI = to.toURI(); String relative = getRelativePath(fromURI.toString(), toURI.toString(), URIUtils.URI_FILE_SEPARATOR); relative = convertUriToPlatformSeparator(relative); return relative; } public static String relativizeSourceURIs(LessSource from, LessSource to) { if (to == null) return null; URI toURI = to.getURI(); if (toURI == null) return to.getName(); String toURIAsString = toURI.toString(); if (from == null) return toURIAsString; URI fromURI = from.getURI(); if (fromURI == null) return toURIAsString; String fromURIAsString = fromURI.toString(); return getRelativePath(fromURIAsString, toURIAsString, URIUtils.URI_FILE_SEPARATOR); } public static String convertUriToPlatformSeparator(String relative) { return relative.replace(URI_FILE_SEPARATOR, Constants.FILE_SEPARATOR); } public static String convertPlatformSeparatorToUri(String relative) { return relative.replace(Constants.FILE_SEPARATOR, URI_FILE_SEPARATOR); } /** * taken from stackoverflow: * http://stackoverflow.com/questions/204784/how-to-construct * -a-relative-path-in-java-from-two-absolute-paths-or-urls * * Get the relative path from one file to another, specifying the directory * separator. If one of the provided resources does not exist, it is assumed * to be a file unless it ends with '/' or '\'. * * @param basePath * basePath is calculated from this file * @param targetPath * targetPath is calculated to this file * @param pathSeparator * directory separator. The platform default is not assumed so that * we can test Unix behaviour when running on Windows (for example) * * @return */ public static String getRelativePath(String basePath, String targetPath, String pathSeparator) { // Normalize the paths String normalizedTargetPath = normalizeNoEndSeparator(targetPath, pathSeparator); String normalizedBasePath = normalizeNoEndSeparator(basePath, pathSeparator); if (normalizedTargetPath==null) return ""; if (normalizedBasePath==null) return targetPath; String[] base = normalizedBasePath.split(Pattern.quote(pathSeparator)); String[] target = normalizedTargetPath.split(Pattern.quote(pathSeparator)); // First get all the common elements. Store them as a string, // and also count how many of them there are. StringBuilder common = new StringBuilder(); int commonIndex = 0; while (commonIndex < target.length && commonIndex < base.length && target[commonIndex].equals(base[commonIndex])) { common.append(target[commonIndex] + pathSeparator); commonIndex++; } if (commonIndex == 0) { // No single common path element. This most // likely indicates differing drive letters, like C: and D:. // These paths cannot be relativized. return normalizedTargetPath; // throw new PathResolutionException("No common path element found for '" + normalizedTargetPath + "' and '" + normalizedBasePath + "'"); } // The number of directories we have to backtrack depends on whether the base is a file or a dir // For example, the relative path from // // /foo/bar/baz/gg/ff to /foo/bar/baz // // ".." if ff is a file // "../.." if ff is a directory // // The following is a heuristic to figure out if the base refers to a file or dir. It's not perfect, because // the resource referred to by this path may not actually exist, but it's the best I can do boolean baseIsFile = true; File baseResource = new File(normalizedBasePath); if (baseResource.exists()) { baseIsFile = baseResource.isFile(); } else if (basePath.endsWith(pathSeparator)) { baseIsFile = false; } StringBuilder relative = new StringBuilder(); if (base.length != commonIndex) { int numDirsUp = baseIsFile ? base.length - commonIndex - 1 : base.length - commonIndex; for (int i = 0; i < numDirsUp; i++) { relative.append(".." + pathSeparator); } } relative.append(safeSubstring(normalizedTargetPath, common.length())); return relative.toString(); } public static String normalizeNoEndSeparator(String path, String separator) { String result = RelativeFilenameUtils.normalizeNoEndSeparator(path); // Undo the changes to the separators made by normalization if ("/".equals(separator)) { result = FilenameUtils.separatorsToUnix(result); } else if ("\\".equals(separator)) { result = FilenameUtils.separatorsToWindows(result); } else { throw new IllegalArgumentException("Unrecognised dir separator '" + separator + "'"); } return result; } private static String safeSubstring(String string, int beginIndex) { if (beginIndex > string.length()) return ""; return string.substring(beginIndex); } public static String addPLatformSlashIfNeeded(String directory) { if (directory.endsWith(Constants.FILE_SEPARATOR)) return directory; return directory + Constants.FILE_SEPARATOR; } public static URI changeSuffix(URI uri, String dottedSuffix) { if (uri==null) return null; URI newUri; try { String uriAsString = uri.toString(); int lastIndexOfDot = uriAsString.lastIndexOf('.'); if(lastIndexOfDot > -1) { newUri = new URI(uriAsString.substring(0, (lastIndexOfDot + 1)) + dottedSuffix); } else { newUri = new URI(uriAsString + dottedSuffix); } } catch (URISyntaxException exception) { throw new IllegalStateException(exception); } return newUri; } public static String changeSuffix(String filename, String dottedSuffix) { if (filename == null) return null; int lastIndexOf = filename.lastIndexOf('.'); if (lastIndexOf == -1) return filename + dottedSuffix; return filename.substring(0, lastIndexOf) + dottedSuffix; } public static String addSuffix(String filename, String dottedSuffix) { if (filename == null) return null; return filename + dottedSuffix; } public static File changeSuffix(File file, String dottedSuffix) { if (file == null) return null; String filename = changeSuffix(file.toString(), dottedSuffix); return new File(filename); } public static FileSource changeSuffix(FileSource source, String dottedSuffix) { if (source == null) return null; return new LessSource.FileSource(changeSuffix(source.getInputFile(), dottedSuffix)); } public static boolean isQuotedUrl(String url) { int length = url.length(); if (length<2) return false; char first = url.charAt(0); char last = url.charAt(length-1); if (first!=last) return false; return first=='\'' || first=='"'; } }