/* URIUtils.java (c) 2015 Edward Swartz All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html */ package v9t9.common.files; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import org.apache.log4j.Logger; import ejs.base.utils.Pair; /** * @author ejs * */ public class URIUtils { private static final Logger logger = Logger.getLogger(PathFileLocator.class); /** * @param uri * @return */ public static Pair<URI, String> splitFileName(URI uri) { URI parent = resolveInsideURI(uri, "."); if (parent.getPath() != null) { int l1 = parent.getPath().length(); String path = uri.getPath(); String name = path.substring(l1); return new Pair<URI, String>(parent, name); } else { int l1 = parent.getSchemeSpecificPart().length(); String path = uri.getSchemeSpecificPart(); String name = path.substring(l1); return new Pair<URI, String>(parent, name); } // String path = uri.toString(); // int idx = path.lastIndexOf('/'); // if (idx == path.length() - 1) // return new Pair<String, String>(path.substring(0, idx + 1), ""); // else if (idx >= 0) // return new Pair<String, String>(path.substring(0, idx + 1), path.substring(idx + 1)); // else // return new Pair<String, String>("", path); } private static URL resolveToLocalZipFile(URL zip) { return zip; } /** * @param uri * @param string * @return */ public static URI resolveInsideURI(URI uri, String string) { if (uri == null) return URI.create(string); URI resolved = null; if (string.contains("/")) { try { resolved = URI.create(string); if (resolved.isOpaque()) { if (!"jar".equals(resolved.getScheme())) return resolved; URI ssp = URI.create(resolved.getSchemeSpecificPart()); if ("file".equals(ssp.getScheme()) || ssp.getScheme() == null) { if (("file".equals(ssp.getScheme()) && !ssp.getSchemeSpecificPart().startsWith("/") || (ssp.getScheme() == null && !ssp.getPath().startsWith("/")))) { String path = uri.getSchemeSpecificPart() + ssp.getSchemeSpecificPart(); int idx = path.lastIndexOf('!'); if (idx >= 0) path = path.substring(0, idx); if (new File(path).exists()) { resolved = URI.create("jar:" + uri + ssp.getSchemeSpecificPart()); return resolved; } } else { return resolved; } } } } catch (IllegalArgumentException e) { } } if (!uri.isOpaque()) { resolved = uri.resolve(encodeURIcomponent(string)); } else { try { // urgh, resolving inside these kinds of URLs does not strip the non-directory suffix // automagically; do it manually String ssp = uri.getSchemeSpecificPart(); if (!ssp.endsWith("/")) { int idx = ssp.lastIndexOf("/"); if (idx >= 0) ssp = ssp.substring(0, idx + 1); } resolved = createURI(ssp).resolve(encodeURIcomponent(string)); resolved = new URI(uri.getScheme() + ":" + resolved.getScheme(), resolved.getUserInfo(), resolved.getHost(), resolved.getPort(), resolved.getPath(), resolved.getQuery(), uri.getFragment()); boolean got = false; try { if ("jar".equals(resolved.getScheme())) { // resolved = resolveToLocalJarFile(resolved.toURL()).toURI(); resolved = resolveToLocalZipFile(resolved.toURL()).toURI(); got = true; } } catch (MalformedURLException e) { logger.error("malformed URL from " + resolved, e); e.printStackTrace(); } catch (URISyntaxException e) { logger.error("URI syntax from " + resolved, e); e.printStackTrace(); } if (got) { logger.debug("Resolved " + uri + " + " + string + " ==> " + resolved); } } catch (URISyntaxException e) { logger.error("URI syntax error " + string, e); e.printStackTrace(); } } return resolved; } /** Converts a string into something you can safely insert into a URL. */ private static String encodeURIcomponent(String s) { StringBuilder o = new StringBuilder(); for (char ch : s.toCharArray()) { if (isUnsafe(ch)) { if (ch < 0x100) { o.append('%'); o.append(toHex((ch >> 4) & 0xf)); o.append(toHex(ch & 0xf)); } else { try { for (byte c : ("" + ch).getBytes("UTF-8")) { o.append('%'); o.append(toHex((c >> 4) & 0xf)); o.append(toHex(c & 0xf)); } } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException(e); } } } else o.append(ch); } return o.toString(); } private static char toHex(int ch) { return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10); } private static boolean isUnsafe(char ch) { if (ch > 128 || ch < 0) return true; // remove '/' since it is likely a real path separator return " %$&+,:;=?@<>#%".indexOf(ch) >= 0; } /** * @param path * @return */ public static URI createURI(String path) throws URISyntaxException { // convert slashes path = path.replace('\\', '/'); // ensure all act like directories if (!path.contains(":/") || path.indexOf(":/") == 1) { int partIdx = path.indexOf("file:"); String pathPart = partIdx >= 0 ? path.substring(partIdx+5) : path; File file = new File(pathPart); String uriPath = file.getAbsolutePath(); // convert slashes uriPath = uriPath.replace('\\', '/'); // windows if (new File(uriPath).isAbsolute() && !uriPath.startsWith("/")) uriPath = "/" + uriPath; uriPath = partIdx >= 0 ? path.substring(0, partIdx + 5) + uriPath : uriPath; path = uriPath; } else { // windows if (new File(path).isAbsolute() && !path.startsWith("/")) path = "/" + path; } // convert bad chars path = path.replace(" ", "%20"); if (!path.endsWith("/")) path += "/"; URI uri = new URI(path); if (uri.getScheme() == null) { uri = new URI("file", uri.getPath(), null); } logger.debug("URI created from " + path + " as " + uri); return uri; } }