/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ package net.ontopia.utils; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.infoset.impl.basic.URILocator; /** * INTERNAL: Utilities for working with URIs. * @since 1.3.2 */ public class URIUtils { /** * INTERNAL: Given a File object, produce a corresponding URILocator * object in the file: URI scheme. */ public static URILocator getFileURI(File file) { try { return new URILocator(toURL(file).toExternalForm()); } catch (java.net.MalformedURLException e) { throw new OntopiaRuntimeException("Malformed URI for File: '" + file + "'", e); } } /** * INTERNAL: Given a File object, produce a corresponding URI string * object in the file: URI scheme. * @since 3.3.0 */ public static String getFileURIString(File file) { try { return toURL(file).toExternalForm(); } catch (java.net.MalformedURLException e) { throw new OntopiaRuntimeException("Impossible error", e); } } /** * INTERNAL: Given a URILocator in the file: URI scheme, produce the * corresponding File object. * @since 1.4 */ public static File getURIFile(LocatorIF file) throws java.net.MalformedURLException { String address = file.getAddress(); if (!file.getNotation().equals("URI")) throw new java.net.MalformedURLException("Not a URI: " + file); if (!address.substring(0, 5).equals("file:")) throw new java.net.MalformedURLException("Not a file URI: " + file); // FIXME: this method is not complete, since it does not support Windows! return new File(address.substring(5)); } /** * INTERNAL: Turns a string containing a url or a filename into a * proper LocatorIF object. */ public static URILocator getURI(String uri_or_filename) { try { // first try interpreting it as a file name (see bug #679) File file = new File(uri_or_filename); if (file.exists()) return new URILocator(file); } catch (java.security.AccessControlException e) { // in an applet we won't be allowed to call this method (see bug #1006) // we solve this by catching the exception and ignoring it } // then try loading it as a resource if (uri_or_filename.startsWith("classpath:")) { try { return new URILocator(StreamUtils.getResource(uri_or_filename)); } catch (java.io.IOException e) { throw new OntopiaRuntimeException(e); } } // if that fails, then pretend it's a URI try { return new URILocator(uri_or_filename); } catch (MalformedURLException e) { // it wasn't a URI, so probably it was a reference to a non-existent file throw new OntopiaRuntimeException("Non-existent file or bad URI: " + uri_or_filename, e); } } /** * INTERNAL: URL-encodes the string by encoding reserved characters * using %-codes. * * @param str String to be URL-encoded. * @param charenc Character encoding to use in URL. Usually UTF-8. */ public static String urlEncode(String str, String charenc) throws IOException { byte[] encodedstr; if (charenc != null) encodedstr = str.getBytes(charenc); else encodedstr = str.getBytes(); // uses platform default, which is bad // however, avoids crash on JDK 1.3 // RFC 2396, section 2.3: // ====================== // Data characters that are allowed in a URI but do not have a reserved // purpose are called unreserved. These include upper and lower case // letters, decimal digits, and a limited set of punctuation marks and // symbols. // // unreserved = alphanum | mark // // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" // // Unreserved characters can be escaped without changing the semantics // of the URI, but this should not be done unless the URI is being used // in a context that does not allow the unescaped character to appear. StringBuilder buf = new StringBuilder(); for (int ix = 0; ix < encodedstr.length; ix++) { if ((encodedstr[ix] >= 'a' && encodedstr[ix] <= 'z') || (encodedstr[ix] >= 'A' && encodedstr[ix] <= 'Z') || (encodedstr[ix] >= '0' && encodedstr[ix] <= '9') || encodedstr[ix] == '-' || encodedstr[ix] == '_' || encodedstr[ix] == '.' || encodedstr[ix] == '!' || encodedstr[ix] == '~' || encodedstr[ix] == '*' || encodedstr[ix] == '\'' || encodedstr[ix] == '(' || encodedstr[ix] == ')') buf.append((char) encodedstr[ix]); // unreserved char else if (encodedstr[ix] == ' ') buf.append('+'); else buf.append("%" + toHexString(encodedstr[ix])); } return buf.toString(); } /** * INTERNAL: Make hex string for integer. */ public static String toHexString(byte n) { return "" + toHexDigit((byte) ((n & 0xF0) >> 4)) + toHexDigit((byte) (n & 0x0F)); } private static char toHexDigit(byte n) { if (n < 10) return (char) ('0' + ((char) n)); else return (char) (((char) (n - 10)) + 'A'); } /** * INTERNAL: Return URILocator from uri string. */ public static URILocator getURILocator(String uri) { try { return new URILocator(uri); } catch (MalformedURLException e) { // it wasn't a URI, so probably it was a reference to a non-existent file throw new OntopiaRuntimeException("Malformed URI:" + uri, e); } } /** * INTERNAL: Use this method instead of File.toURL() to get URLs for files. */ public static URL toURL(File file) throws MalformedURLException { return file.toURI().toURL(); } }