summaryrefslogtreecommitdiffstats
path: root/src/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com')
-rw-r--r--src/java/com/jogamp/common/jvm/JNILibLoaderBase.java36
-rw-r--r--src/java/com/jogamp/common/net/AssetURLContext.java2
-rw-r--r--src/java/com/jogamp/common/net/Uri.java2170
-rw-r--r--src/java/com/jogamp/common/os/Platform.java8
-rw-r--r--src/java/com/jogamp/common/util/IOUtil.java330
-rw-r--r--src/java/com/jogamp/common/util/JarUtil.java301
-rw-r--r--src/java/com/jogamp/common/util/cache/TempJarCache.java156
7 files changed, 2435 insertions, 568 deletions
diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
index 4bb68d3..9b1865f 100644
--- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
+++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
@@ -42,7 +42,6 @@ package com.jogamp.common.jvm;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.AccessController;
@@ -52,8 +51,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.os.NativeLibrary;
-import com.jogamp.common.util.IOUtil;
import com.jogamp.common.util.JarUtil;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.cache.TempJarCache;
@@ -155,7 +154,7 @@ public class JNILibLoaderBase {
/**
*
* @param classFromJavaJar
- * @param classJarURI
+ * @param classJarUri
* @param jarBasename jar basename w/ suffix
* @param nativeJarBasename native jar basename w/ suffix
* @return
@@ -163,15 +162,15 @@ public class JNILibLoaderBase {
* @throws SecurityException
* @throws URISyntaxException
*/
- private static final boolean addNativeJarLibsImpl(final Class<?> classFromJavaJar, final URI classJarURI,
- final String jarBasename, final String nativeJarBasename)
+ private static final boolean addNativeJarLibsImpl(final Class<?> classFromJavaJar, final Uri classJarUri,
+ final Uri.Encoded jarBasename, final Uri.Encoded nativeJarBasename)
throws IOException, SecurityException, URISyntaxException
{
if (DEBUG) {
final StringBuilder msg = new StringBuilder();
msg.append("JNILibLoaderBase: addNativeJarLibsImpl(").append(PlatformPropsImpl.NEWLINE);
msg.append(" classFromJavaJar = ").append(classFromJavaJar).append(PlatformPropsImpl.NEWLINE);
- msg.append(" classJarURI = ").append(classJarURI).append(PlatformPropsImpl.NEWLINE);
+ msg.append(" classJarURI = ").append(classJarUri).append(PlatformPropsImpl.NEWLINE);
msg.append(" jarBasename = ").append(jarBasename).append(PlatformPropsImpl.NEWLINE);
msg.append(" os.and.arch = ").append(PlatformPropsImpl.os_and_arch).append(PlatformPropsImpl.NEWLINE);
msg.append(" nativeJarBasename = ").append(nativeJarBasename).append(PlatformPropsImpl.NEWLINE);
@@ -181,15 +180,15 @@ public class JNILibLoaderBase {
boolean ok = false;
- final URI jarSubURI = JarUtil.getJarSubURI( classJarURI );
+ final Uri jarSubURI = classJarUri.getContainedUri();
if (null == jarSubURI) {
- throw new IllegalArgumentException("JarSubURI is null of: "+classJarURI);
+ throw new IllegalArgumentException("JarSubURI is null of: "+classJarUri);
}
- final String jarUriRoot_s = IOUtil.getURIDirname( jarSubURI.toString() );
+ final Uri jarSubUriRoot = jarSubURI.getDirectory();
if (DEBUG) {
- System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: initial: %s -> %s%n", jarSubURI, jarUriRoot_s);
+ System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: initial: %s -> %s%n", jarSubURI, jarSubUriRoot);
}
final String nativeLibraryPath = String.format("natives/%s/", PlatformPropsImpl.os_and_arch);
@@ -201,7 +200,7 @@ public class JNILibLoaderBase {
if (null != nativeLibraryURI) {
// We probably have one big-fat jar file, containing java classes
// and all native platform libraries under 'natives/os.and.arch'!
- final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot_s+jarBasename);
+ final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
try {
if( TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath) ) {
ok = true;
@@ -218,7 +217,7 @@ public class JNILibLoaderBase {
}
if (!ok) {
// We assume one slim native jar file per 'os.and.arch'!
- final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot_s+nativeJarBasename);
+ final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(nativeJarBasename) );
if (DEBUG) {
System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: module: %s -> %s%n", nativeJarBasename, nativeJarURI);
@@ -247,13 +246,13 @@ public class JNILibLoaderBase {
}
}
final String os_and_arch_dot = PlatformPropsImpl.os_and_arch.replace('-', '.');
- final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG" ; // TODO: sync with gluegen-cpptasks-base.xml
+ final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG"; // TODO: sync with gluegen-cpptasks-base.xml
try {
if(DEBUG) {
System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
moduleName, os_and_arch_dot, nativeJarTagClassName);
}
- final URI nativeJarTagClassJarURI = JarUtil.getJarURI(nativeJarTagClassName, cl);
+ final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
if (DEBUG) {
System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
}
@@ -399,14 +398,14 @@ public class JNILibLoaderBase {
}
final ClassLoader cl = c.getClassLoader();
- final URI classJarURI = JarUtil.getJarURI(c.getName(), cl);
- final String jarName = JarUtil.getJarBasename(classJarURI);
+ final Uri classJarURI = JarUtil.getJarUri(c.getName(), cl);
+ final Uri.Encoded jarName = JarUtil.getJarBasename(classJarURI);
if (jarName == null) {
continue;
}
- final String jarBasename = jarName.substring(0, jarName.indexOf(".jar"));
+ final Uri.Encoded jarBasename = jarName.substring(0, jarName.indexOf(".jar"));
if(DEBUG) {
System.err.printf("JNILibLoaderBase: jarBasename: %s%n", jarBasename);
@@ -423,7 +422,8 @@ public class JNILibLoaderBase {
}
}
- final String nativeJarBasename = String.format("%s-natives-%s.jar", jarBasename, PlatformPropsImpl.os_and_arch);
+ final Uri.Encoded nativeJarBasename =
+ Uri.Encoded.cast( String.format("%s-natives-%s.jar", jarBasename.get(), PlatformPropsImpl.os_and_arch) );
ok = JNILibLoaderBase.addNativeJarLibsImpl(c, classJarURI, jarName, nativeJarBasename);
if (ok) {
diff --git a/src/java/com/jogamp/common/net/AssetURLContext.java b/src/java/com/jogamp/common/net/AssetURLContext.java
index 2ada3c6..af90c01 100644
--- a/src/java/com/jogamp/common/net/AssetURLContext.java
+++ b/src/java/com/jogamp/common/net/AssetURLContext.java
@@ -185,7 +185,7 @@ public abstract class AssetURLContext implements PiggybackURLContext {
try {
final File file = new File(path);
if(file.exists()) {
- url = IOUtil.toURISimple(file).toURL();
+ url = Uri.valueOf(file).toURL();
conn = open(url);
type = null != conn ? 3 : -1;
}
diff --git a/src/java/com/jogamp/common/net/Uri.java b/src/java/com/jogamp/common/net/Uri.java
new file mode 100644
index 0000000..d1f2016
--- /dev/null
+++ b/src/java/com/jogamp/common/net/Uri.java
@@ -0,0 +1,2170 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2006, 2010 The Apache Software Foundation.
+ *
+ * This code is derived from the Apache Harmony project's {@code class java.net.URI.Helper},
+ * and has been heavily modified for GlueGen/JogAmp.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the LICENSE.txt file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 com.jogamp.common.net;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+import jogamp.common.Debug;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.PropertyAccess;
+
+/**
+ * This class implements an immutable Uri as defined by <a href="https://tools.ietf.org/html/rfc2396">RFC 2396</a>.
+ * <p>
+ * Character encoding is employed as defined by <a href="https://tools.ietf.org/html/rfc3986">RFC 3986</a>,
+ * see <a href="https://tools.ietf.org/html/rfc3986#section-2.1">RFC 3986 section 2.1</a>,
+ * while multibyte unicode characters are preserved in encoded parts.
+ * </p>
+ *
+ * <pre>
+ 1 [scheme:]scheme-specific-part[#fragment]
+ 2 [scheme:][//authority]path[?query][#fragment]
+ 3 [scheme:][//[user-info@]host[:port]]path[?query][#fragment]
+
+ scheme-specific-part: [//authority]path[?query]
+ authority: [user-info@]host[:port]
+ * </pre>
+ * <p>
+ * <a href="https://tools.ietf.org/html/rfc3986#section-2.2">RFC 3986 section 2.2</a> <i>Reserved Characters</i> (January 2005)
+ * <table border="1">
+ <tr>
+ <td><code>!</code></td>
+ <td><code>*</code></td>
+ <td><code>'</code></td>
+ <td><code>(</code></td>
+ <td><code>)</code></td>
+ <td><code>;</code></td>
+ <td><code>:</code></td>
+ <td><code>@</code></td>
+ <td><code>&amp;</code></td>
+ <td><code>=</code></td>
+ <td><code>+</code></td>
+ <td><code>$</code></td>
+ <td><code>,</code></td>
+ <td><code>/</code></td>
+ <td><code>?</code></td>
+ <td><code>#</code></td>
+ <td><code>[</code></td>
+ <td><code>]</code></td>
+ </tr>
+ * </table>
+ * </p>
+ * <p>
+ * <a href="https://tools.ietf.org/html/rfc3986#section-2.3">RFC 3986 section 2.3</a> <i>Unreserved Characters</i> (January 2005)
+ * <table border="1">
+ <tr>
+ <td><code>A</code></td>
+ <td><code>B</code></td>
+ <td><code>C</code></td>
+ <td><code>D</code></td>
+ <td><code>E</code></td>
+ <td><code>F</code></td>
+ <td><code>G</code></td>
+ <td><code>H</code></td>
+ <td><code>I</code></td>
+ <td><code>J</code></td>
+ <td><code>K</code></td>
+ <td><code>L</code></td>
+ <td><code>M</code></td>
+ <td><code>N</code></td>
+ <td><code>O</code></td>
+ <td><code>P</code></td>
+ <td><code>Q</code></td>
+ <td><code>R</code></td>
+ <td><code>S</code></td>
+ <td><code>T</code></td>
+ <td><code>U</code></td>
+ <td><code>V</code></td>
+ <td><code>W</code></td>
+ <td><code>X</code></td>
+ <td><code>Y</code></td>
+ <td><code>Z</code></td>
+ </tr>
+ <tr>
+ <td><code>a</code></td>
+ <td><code>b</code></td>
+ <td><code>c</code></td>
+ <td><code>d</code></td>
+ <td><code>e</code></td>
+ <td><code>f</code></td>
+ <td><code>g</code></td>
+ <td><code>h</code></td>
+ <td><code>i</code></td>
+ <td><code>j</code></td>
+ <td><code>k</code></td>
+ <td><code>l</code></td>
+ <td><code>m</code></td>
+ <td><code>n</code></td>
+ <td><code>o</code></td>
+ <td><code>p</code></td>
+ <td><code>q</code></td>
+ <td><code>r</code></td>
+ <td><code>s</code></td>
+ <td><code>t</code></td>
+ <td><code>u</code></td>
+ <td><code>v</code></td>
+ <td><code>w</code></td>
+ <td><code>x</code></td>
+ <td><code>y</code></td>
+ <td><code>z</code></td>
+ </tr>
+ <tr>
+ <td><code>0</code></td>
+ <td><code>1</code></td>
+ <td><code>2</code></td>
+ <td><code>3</code></td>
+ <td><code>4</code></td>
+ <td><code>5</code></td>
+ <td><code>6</code></td>
+ <td><code>7</code></td>
+ <td><code>8</code></td>
+ <td><code>9</code></td>
+ <td><code>-</code></td>
+ <td><code>_</code></td>
+ <td><code>.</code></td>
+ <td><code>~</code></td>
+ </tr>
+ * </table>
+ * </p>
+ * <p>
+ * Other characters in a Uri must be percent encoded.
+ * </p>
+ * @since 2.2.1
+ */
+public class Uri {
+ private static final boolean DEBUG;
+ private static final boolean DEBUG_SHOWFIX;
+
+ static {
+ Debug.initSingleton();
+ DEBUG = IOUtil.DEBUG || Debug.debug("Uri");
+ DEBUG_SHOWFIX = PropertyAccess.isPropertyDefined("jogamp.debug.Uri.ShowFix", true);
+ }
+
+ /**
+ * Usually used to fix a path from a previously contained and opaque Uri,
+ * i.e. {@link #getContainedUri()}.
+ * <p>
+ * Such an opaque Uri w/ erroneous encoding may have been injected via
+ * {@link #valueOf(URI)} and {@link #valueOf(URL)} where the given URL or URI was opaque!
+ * </p>
+ * <p>
+ * This remedies issues when dealing w/ java URI/URL opaque sources,
+ * which do not comply to the spec, i.e. containe un-encoded chars, e.g. ':', '$', ..
+ * </p>
+ */
+ private static final int PARSE_HINT_FIX_PATH = 1 << 0;
+
+ private static final String DIGITS = "0123456789ABCDEF";
+
+ private static final String ENCODING = "UTF8";
+ private static final String MSG_ENCODING_NA = "Charset UTF8 not available";
+ private static final Pattern patternSingleFS = Pattern.compile("/{1}");
+
+ /**
+ * RFC 3986 section 2.3 Unreserved Characters (January 2005)
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String UNRESERVED = "_-.~";
+ // Harmony: _ - ! . ~ ' ( ) *
+
+ private static final String punct = ",;:$&+=";
+ // Harmony: , ; : $ & + =
+
+ /**
+ * RFC 3986 section 2.2 Reserved Characters (January 2005)
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String RESERVED = punct + "!*\'()@/?#[]";
+ // Harmony: , ; : $ & + = ? / [ ] @
+
+ public static final String RESERVED_2 = punct + "!*\'()@/?[]";
+ // Harmony: , ; : $ & + = ? / [ ] @
+
+ // Bug 908, issues w/ windows file path char: $ ^ ~ # [ ]
+ // Windows invalid File characters: * ? " < > |
+
+ /**
+ * Valid charset for RFC 2396 {@code authority}'s {@code user-info},
+ * additional to legal {@code alphanum} characters.
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String USERINFO_LEGAL = UNRESERVED + punct;
+ // Harmony: someLegal = unreserved + punct -> _ - ! . ~ ' ( ) * , ; : $ & + =
+
+ /**
+ * Valid charset for RFC 2396 {@code authority},
+ * additional to legal {@code alphanum} characters.
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String AUTHORITY_LEGAL = "@[]" + USERINFO_LEGAL;
+
+ /**
+ * Valid charset for RFC 2396 {@code path},
+ * additional to legal {@code alphanum} characters.
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String PATH_LEGAL = "/!" + UNRESERVED; // no RESERVED chars but '!', to allow JAR Uris;
+ // Harmony: "/@" + unreserved + punct -> / @ _ - ! . ~ \ ' ( ) * , ; : $ & + =
+
+ /**
+ * Valid charset for RFC 2396 {@code query},
+ * additional to legal {@code alphanum} characters.
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String QUERY_LEGAL = UNRESERVED + RESERVED_2 + "\\\"";
+ // Harmony: unreserved + reserved + "\\\""
+
+ /**
+ * Valid charset for RFC 2396 {@code scheme-specific-part},
+ * additional to legal {@code alphanum} characters.
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String SSP_LEGAL = QUERY_LEGAL;
+ // Harmony: unreserved + reserved
+
+ /**
+ * Valid charset for RFC 2396 {@code fragment},
+ * additional to legal {@code alphanum} characters.
+ * <p>
+ * {@value} + {@code alphanum}
+ * </p>
+ */
+ public static final String FRAG_LEGAL = UNRESERVED + RESERVED;
+ // Harmony: unreserved + reserved
+
+ /** {@value} */
+ public static final char SCHEME_SEPARATOR = ':';
+ /** {@value} */
+ public static final char FRAGMENT_SEPARATOR = '#';
+ /** {@value} */
+ public static final String FILE_SCHEME = "file";
+ /** {@value} */
+ public static final String HTTP_SCHEME = "http";
+ /** {@value} */
+ public static final String HTTPS_SCHEME = "https";
+ /** {@value} */
+ public static final String JAR_SCHEME = "jar";
+ /** A JAR sub-protocol is separated from the JAR entry w/ this separator {@value}. Even if no class is specified '!/' must follow!. */
+ public static final char JAR_SCHEME_SEPARATOR = '!';
+
+ /**
+ * Immutable RFC3986 encoded string.
+ */
+ public static class Encoded implements Comparable<Encoded>, CharSequence {
+ private final String s;
+
+ /**
+ * Casts the given encoded String by creating a new Encoded instance.
+ * <p>
+ * No encoding will be performed, use with care.
+ * </p>
+ */
+ public static Encoded cast(final String encoded) {
+ return new Encoded(encoded);
+ }
+
+ Encoded(final String encodedString) {
+ this.s = encodedString;
+ }
+
+ /**
+ * Encodes all characters into their hexadecimal value prepended by '%', except:
+ * <ol>
+ * <li>letters ('a'..'z', 'A'..'Z')</li>
+ * <li>numbers ('0'..'9')</li>
+ * <li>characters in the legal-set parameter</li>
+ * <li> others (unicode characters that are not in
+ * US-ASCII set, and are not ISO Control or are not ISO Space characters)</li>
+ * </ol>
+ * <p>
+ * Uses {@link Uri#encode(String, String)} for implementation..
+ * </p>
+ *
+ * @param vanilla the string to be encoded
+ * @param legal extended character set, allowed to be preserved in the vanilla string
+ */
+ public Encoded(final String vanilla, final String legal) {
+ this.s = encode(vanilla, legal);
+ }
+
+ public boolean isASCII() { return false; }
+
+ /** Returns the encoded String */
+ public final String get() { return s; }
+
+ /**
+ * Decodes the string argument which is assumed to be encoded in the {@code
+ * x-www-form-urlencoded} MIME content type using the UTF-8 encoding scheme.
+ * <p>
+ *'%' and two following hex digit characters are converted to the
+ * equivalent byte value. All other characters are passed through
+ * unmodified.
+ * </p>
+ * <p>
+ * e.g. "A%20B%20C %24%25" -> "A B C $%"
+ * </p>
+ * <p>
+ * Uses {@link Uri#decode(String)} for implementation..
+ * </p>
+ */
+ public final String decode() { return Uri.decode(s); }
+
+ //
+ // Basic Object / Identity
+ //
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns the encoded String, same as {@link #get()}.
+ * </p>
+ */
+ @Override
+ public final String toString() { return s; }
+
+ @Override
+ public final int hashCode() { return s.hashCode(); }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param o The comparison argument, either a {@link Encoded} or a {@link String}
+ *
+ * @return {@code true} if the given object is equivalent to this instance,
+ * otherwise {@code false}.
+ *
+ * @see #compareTo(Encoded)
+ * @see #equalsIgnoreCase(Encoded)
+ */
+ @Override
+ public final boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof Encoded) {
+ return s.equals(((Encoded)o).s);
+ }
+ return s.equals(o);
+ }
+
+ //
+ // CharSequence
+ //
+
+ @Override
+ public final int length() { return s.length(); }
+
+ @Override
+ public final char charAt(final int index) { return s.charAt(index); }
+
+ @Override
+ public final CharSequence subSequence(final int start, final int end) { return s.subSequence(start, end); }
+
+ @Override
+ public final int compareTo(final Encoded o) { return s.compareTo(o.s); }
+
+ //
+ // String derived ..
+ //
+ /** See {@link String#concat(String)}. */
+ public Encoded concat(final Encoded encoded) { return new Encoded(s.concat(encoded.s)); }
+
+ /** See {@link String#substring(int)}. */
+ public final Encoded substring(final int start) { return new Encoded(s.substring(start)); }
+ /** See {@link String#substring(int, int)}. */
+ public final Encoded substring(final int start, final int end) { return new Encoded(s.substring(start, end)); }
+
+ /** See {@link String#indexOf(int)}. */
+ public final int indexOf(final int ch) { return s.indexOf(ch); }
+ /** See {@link String#indexOf(int, int)}. */
+ public final int indexOf(final int ch, final int fromIndex) { return s.indexOf(ch, fromIndex); }
+ /** See {@link String#indexOf(String)}. */
+ public final int indexOf(final String str) { return s.indexOf(str); }
+ /** See {@link String#indexOf(String, int)}. */
+ public final int indexOf(final String str, final int fromIndex) { return s.indexOf(str, fromIndex); }
+
+ /** See {@link String#lastIndexOf(int)}. */
+ public final int lastIndexOf(final int ch) { return s.lastIndexOf(ch); }
+ /** See {@link String#lastIndexOf(int, int)}. */
+ public int lastIndexOf(final int ch, final int fromIndex) { return s.lastIndexOf(ch, fromIndex); }
+ /** See {@link String#lastIndexOf(String)}. */
+ public int lastIndexOf(final String str) { return s.lastIndexOf(str); }
+ /** See {@link String#lastIndexOf(String, int)}. */
+ public int lastIndexOf(final String str, final int fromIndex) { return s.lastIndexOf(str, fromIndex); }
+
+ /** See {@link String#startsWith(String, int)} */
+ public boolean startsWith(final String prefix, final int toffset) { return s.startsWith(prefix, toffset); }
+ /** See {@link String#endsWith(String)} */
+ public boolean endsWith(final String suffix) { return s.endsWith(suffix); }
+
+ /** See {@link String#equalsIgnoreCase(String)}. */
+ public final boolean equalsIgnoreCase(final Encoded anotherEncoded) { return s.equalsIgnoreCase(anotherEncoded.s); }
+ }
+
+ public static class ASCIIEncoded extends Encoded {
+ /**
+ * Casts the given encoded String by creating a new ASCIIEncoded instance.
+ * <p>
+ * No encoding will be performed, use with care.
+ * </p>
+ */
+ public static ASCIIEncoded cast(final String encoded) {
+ return new ASCIIEncoded(encoded, null);
+ }
+ private ASCIIEncoded(final String encoded, final Object unused) {
+ super(encoded);
+ }
+
+ /**
+ * Other characters, which are Unicode chars that are not US-ASCII, and are
+ * not ISO Control or are not ISO Space chars are not preserved
+ * and encoded into their hexidecimal value prepended by '%'.
+ * <p>
+ * For example: Euro currency symbol -> "%E2%82%AC".
+ * </p>
+ * <p>
+ * Uses {@link Uri#encodeToASCIIString(String)} for implementation.
+ * </p>
+ * @param unicode unencoded input
+ */
+ public ASCIIEncoded(final String unicode) {
+ super(encodeToASCIIString(unicode));
+ }
+ public boolean isASCII() { return true; }
+ }
+
+ private static void encodeChar2UTF8(final StringBuilder buf, final char ch) {
+ final byte[] bytes;
+ try {
+ bytes = new String(new char[] { ch }).getBytes(ENCODING);
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException(MSG_ENCODING_NA, e);
+ }
+ // FIXME: UTF-8 produces more than one byte ? Optimization might be possible.
+ for (int j = 0; j < bytes.length; j++) {
+ final byte b = bytes[j];
+ buf.append('%');
+ buf.append(DIGITS.charAt( ( b & 0xf0 ) >> 4 ));
+ buf.append(DIGITS.charAt( b & 0xf ));
+ }
+ }
+
+ /**
+ * All characters are encoded into their hexadecimal value prepended by '%', except:
+ * <ol>
+ * <li>letters ('a'..'z', 'A'..'Z')</li>
+ * <li>numbers ('0'..'9')</li>
+ * <li>characters in the legal-set parameter</li>
+ * <li> others (unicode characters that are not in
+ * US-ASCII set, and are not ISO Control or are not ISO Space characters)</li>
+ * </ol>
+ * <p>
+ * Use {@link #encodeToASCIIString(String)} for US-ASCII encoding.
+ * </p>
+ * <p>
+ * Consider using {@link Encoded#Encoded(String, String)} in APIs
+ * to distinguish encoded from unencoded data by type.
+ * </p>
+ *
+ * @param vanilla the string to be encoded
+ * @param legal extended character set, allowed to be preserved in the vanilla string
+ * @return java.lang.String the converted string
+ */
+ public static String encode(final String vanilla, final String legal) {
+ if( null == vanilla ) {
+ return null;
+ }
+ final StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < vanilla.length(); i++) {
+ final char ch = vanilla.charAt(i);
+ if ( (ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ legal.indexOf(ch) > -1 ||
+ ( ch > 127 && !Character.isSpaceChar(ch) && !Character.isISOControl(ch) )
+ ) {
+ buf.append(ch);
+ } else {
+ encodeChar2UTF8(buf, ch);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Other characters, which are Unicode chars that are not US-ASCII, and are
+ * not ISO Control or are not ISO Space chars are not preserved
+ * and encoded into their hexidecimal value prepended by '%'.
+ * <p>
+ * For example: Euro currency symbol -> "%E2%82%AC".
+ * </p>
+ * <p>
+ * Consider using {@link ASCIIEncoded#ASCIIEncoded(String)} in APIs
+ * to distinguish encoded from unencoded data by type.
+ * </p>
+ * @param unicode string to be converted
+ * @return java.lang.String the converted string
+ */
+ public static String encodeToASCIIString(final String unicode) {
+ final StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < unicode.length(); i++) {
+ final char ch = unicode.charAt(i);
+ if (ch <= 127) {
+ buf.append(ch);
+ } else {
+ encodeChar2UTF8(buf, ch);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Safe {@link Encoded#decode()} call on optional {@code encoded} instance.
+ * @param encoded {@link Encoded} instance to be decoded, may be {@code null}.
+ * @return the {@link Encoded#decode() decoded} String or {@code null} if {@code encoded} was {@code null}.
+ */
+ public static String decode(final Encoded encoded) {
+ return null != encoded ? encoded.decode() : null;
+ }
+
+ /**
+ * Decodes the string argument which is assumed to be encoded in the {@code
+ * x-www-form-urlencoded} MIME content type using the UTF-8 encoding scheme.
+ * <p>
+ *'%' and two following hex digit characters are converted to the
+ * equivalent byte value. All other characters are passed through
+ * unmodified.
+ * </p>
+ * <p>
+ * e.g. "A%20B%20C %24%25" -> "A B C $%"
+ * </p>
+ *
+ * @param encoded The encoded string.
+ * @return java.lang.String The decoded version.
+ */
+ public static String decode(final String encoded) {
+ if( null == encoded ) {
+ return null;
+ }
+ final StringBuilder result = new StringBuilder();
+ final byte[] buf = new byte[32];
+ int bufI = 0;
+ for (int i = 0; i < encoded.length();) {
+ final char c = encoded.charAt(i);
+ if (c == '%') {
+ bufI = 0;
+ do {
+ if (i + 2 >= encoded.length()) {
+ throw new IllegalArgumentException("missing '%' hex-digits at index "+i);
+ }
+ final int d1 = Character.digit(encoded.charAt(i + 1), 16);
+ final int d2 = Character.digit(encoded.charAt(i + 2), 16);
+ if (d1 == -1 || d2 == -1) {
+ throw new IllegalArgumentException("invalid hex-digits at index "+i+": "+encoded.substring(i, i + 3));
+ }
+ buf[bufI++] = (byte) ((d1 << 4) + d2);
+ if( 32 == bufI ) {
+ appendUTF8(result, buf, bufI);
+ bufI = 0;
+ }
+ i += 3;
+ } while (i < encoded.length() && encoded.charAt(i) == '%');
+ if( 0 < bufI ) {
+ appendUTF8(result, buf, bufI);
+ }
+ } else {
+ result.append(c);
+ i++;
+ }
+ }
+ return result.toString();
+ }
+ private static void appendUTF8(final StringBuilder sb, final byte[] buf, final int count) {
+ try {
+ sb.append(new String(buf, 0, count, ENCODING));
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException(MSG_ENCODING_NA, e);
+ }
+ }
+
+ /**
+ * Creates a new Uri instance using the given arguments.
+ * <p>
+ * This constructor first creates a temporary Uri string from the given components. This
+ * string will be parsed later on to create the Uri instance.
+ * </p>
+ * <p>
+ * {@code [scheme:]scheme-specific-part[#fragment]}
+ * </p>
+ *
+ * @param scheme the unencoded scheme part of the Uri.
+ * @param ssp the unencoded scheme-specific-part of the Uri.
+ * @param fragment the unencoded fragment part of the Uri.
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri create(final String scheme, final String ssp, final String fragment) throws URISyntaxException {
+ if ( emptyString(scheme) && emptyString(ssp) && emptyString(fragment) ) {
+ throw new URISyntaxException("", "all empty parts");
+ }
+ final StringBuilder uri = new StringBuilder();
+ if ( !emptyString(scheme) ) {
+ uri.append(scheme);
+ uri.append(SCHEME_SEPARATOR);
+ }
+ if ( !emptyString(ssp) ) {
+ // QUOTE ILLEGAL CHARACTERS
+ uri.append(encode(ssp, SSP_LEGAL));
+ }
+ if ( !emptyString(fragment) ) {
+ uri.append(FRAGMENT_SEPARATOR);
+ // QUOTE ILLEGAL CHARACTERS
+ uri.append(encode(fragment, FRAG_LEGAL));
+ }
+ return new Uri(new Encoded(uri.toString()), false, 0);
+ }
+
+ /**
+ * Creates a new Uri instance using the given arguments.
+ * <p>
+ * This constructor first creates a temporary Uri string from the given components. This
+ * string will be parsed later on to create the Uri instance.
+ * </p>
+ * <p>
+ * {@code [scheme:][user-info@]host[:port][path][?query][#fragment]}
+ * </p>
+ *
+ * @param scheme the unencoded scheme part of the Uri.
+ * @param userinfo the unencoded user information of the Uri for authentication and authorization.
+ * @param host the unencoded host name of the Uri.
+ * @param port the port number of the Uri.
+ * @param path the unencoded path to the resource on the host.
+ * @param query the unencoded query part of the Uri to specify parameters for the resource.
+ * @param fragment the unencoded fragment part of the Uri.
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri create (final String scheme, final String userinfo, String host, final int port,
+ final String path, final String query, final String fragment) throws URISyntaxException {
+ if ( emptyString(scheme) && emptyString(userinfo) && emptyString(host) && emptyString(path) &&
+ emptyString(query) && emptyString(fragment) ) {
+ throw new URISyntaxException("", "all empty parts");
+ }
+
+ if ( !emptyString(scheme) && !emptyString(path) && path.length() > 0 && path.charAt(0) != '/') {
+ throw new URISyntaxException(path, "path doesn't start with '/'");
+ }
+
+ final StringBuilder uri = new StringBuilder();
+ if ( !emptyString(scheme) ) {
+ uri.append(scheme);
+ uri.append(SCHEME_SEPARATOR);
+ }
+
+ if ( !emptyString(userinfo) || !emptyString(host) || port != -1) {
+ uri.append("//");
+ }
+
+ if ( !emptyString(userinfo) ) {
+ // QUOTE ILLEGAL CHARACTERS in userinfo
+ uri.append(encode(userinfo, USERINFO_LEGAL));
+ uri.append('@');
+ }
+
+ if ( !emptyString(host) ) {
+ // check for ipv6 addresses that hasn't been enclosed
+ // in square brackets
+ if (host.indexOf(SCHEME_SEPARATOR) != -1 && host.indexOf(']') == -1
+ && host.indexOf('[') == -1) {
+ host = "[" + host + "]";
+ }
+ uri.append(host);
+ }
+
+ if ( port != -1 ) {
+ uri.append(SCHEME_SEPARATOR);
+ uri.append(port);
+ }
+
+ if ( !emptyString(path) ) {
+ // QUOTE ILLEGAL CHARS
+ uri.append(encode(path, PATH_LEGAL));
+ }
+
+ if ( !emptyString(query) ) {
+ uri.append('?');
+ // QUOTE ILLEGAL CHARS
+ uri.append(encode(query, QUERY_LEGAL));
+ }
+
+ if ( !emptyString(fragment) ) {
+ // QUOTE ILLEGAL CHARS
+ uri.append(FRAGMENT_SEPARATOR);
+ uri.append(encode(fragment, FRAG_LEGAL));
+ }
+ return new Uri(new Encoded(uri.toString()), true, 0);
+ }
+
+ /**
+ * Creates a new Uri instance using the given arguments.
+ * <p>
+ * This constructor first creates a temporary Uri string from the given components. This
+ * string will be parsed later on to create the Uri instance.
+ * </p>
+ * <p>
+ * {@code [scheme:]host[path][#fragment]}
+ * </p>
+ *
+ * @param scheme the unencoded scheme part of the Uri.
+ * @param host the unencoded host name of the Uri.
+ * @param path the unencoded path to the resource on the host.
+ * @param fragment the unencoded fragment part of the Uri.
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri create(final String scheme, final String host, final String path, final String fragment) throws URISyntaxException {
+ return create(scheme, null, host, -1, path, null, fragment);
+ }
+
+ /**
+ * Creates a new Uri instance using the given arguments.
+ * <p>
+ * This constructor first creates a temporary Uri string from the given components. This
+ * string will be parsed later on to create the Uri instance.
+ * </p>
+ * <p>
+ * {@code [scheme:][//authority][path][?query][#fragment]}
+ * </p>
+ *
+ * @param scheme the unencoded scheme part of the Uri.
+ * @param authority the unencoded authority part of the Uri.
+ * @param path the unencoded path to the resource on the host.
+ * @param query the unencoded query part of the Uri to specify parameters for the resource.
+ * @param fragment the unencoded fragment part of the Uri.
+ *
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri create(final String scheme, final String authority, final String path, final String query, final String fragment) throws URISyntaxException {
+ if ( emptyString(scheme) && emptyString(authority) && emptyString(path) &&
+ emptyString(query) && emptyString(fragment) ) {
+ throw new URISyntaxException("", "all empty parts");
+ }
+ if ( !emptyString(scheme) && !emptyString(path) && path.length() > 0 && path.charAt(0) != '/') {
+ throw new URISyntaxException(path, "path doesn't start with '/'");
+ }
+
+ final StringBuilder uri = new StringBuilder();
+ if ( !emptyString(scheme) ) {
+ uri.append(scheme);
+ uri.append(SCHEME_SEPARATOR);
+ }
+ if ( !emptyString(authority) ) {
+ uri.append("//");
+ // QUOTE ILLEGAL CHARS
+ uri.append(encode(authority, AUTHORITY_LEGAL));
+ }
+
+ if ( !emptyString(path) ) {
+ // QUOTE ILLEGAL CHARS
+ uri.append(encode(path, PATH_LEGAL));
+ }
+ if ( !emptyString(query) ) {
+ // QUOTE ILLEGAL CHARS
+ uri.append('?');
+ uri.append(encode(query, QUERY_LEGAL));
+ }
+ if ( !emptyString(fragment) ) {
+ // QUOTE ILLEGAL CHARS
+ uri.append(FRAGMENT_SEPARATOR);
+ uri.append(encode(fragment, FRAG_LEGAL));
+ }
+ return new Uri(new Encoded(uri.toString()), false, 0);
+ }
+
+ /**
+ * Casts the given encoded String to a {@link Encoded#cast(String) new Encoded instance}
+ * used to create the resulting Uri instance via {@link #Uri(Encoded)}.
+ * <p>
+ * No encoding will be performed on the given {@code encodedUri}, use with care.
+ * </p>
+ * @throws URISyntaxException
+ */
+ public static Uri cast(final String encodedUri) throws URISyntaxException {
+ return new Uri(Encoded.cast(encodedUri));
+ }
+
+ /**
+ * Creates a new Uri instance using the given file-path argument.
+ * <p>
+ * This constructor first creates a temporary Uri string from the given components. This
+ * string will be parsed later on to create the Uri instance.
+ * </p>
+ * <p>
+ * {@code file:path}
+ * </p>
+ *
+ * @param path the path of the {@code file} {@code schema}.
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri valueOfFilepath(final String path) throws URISyntaxException {
+ if ( emptyString(path) ) {
+ throw new URISyntaxException("", "empty path");
+ }
+ if ( path.charAt(0) != '/' ) {
+ throw new URISyntaxException(path, "path doesn't start with '/'");
+ }
+
+ final StringBuilder uri = new StringBuilder();
+ uri.append(FILE_SCHEME);
+ uri.append(SCHEME_SEPARATOR);
+
+ // QUOTE ILLEGAL CHARS
+ uri.append(encode(path, PATH_LEGAL));
+
+ return new Uri(new Encoded(uri.toString()), false, 0);
+ }
+
+ /**
+ * Creates a new Uri instance using the given File instance.
+ * <p>
+ * This constructor first creates a temporary Uri string from the given components. This
+ * string will be parsed later on to create the Uri instance.
+ * </p>
+ * <p>
+ * {@code file:path}
+ * </p>
+ *
+ * @param file using {@link IOUtil#slashify(String, boolean, boolean) slashified} {@link File#getAbsolutePath() absolute-path}
+ * for the path of the {@code file} {@code schema}, utilizing {@link #valueOfFilepath(String)}.
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri valueOf(final File file) throws URISyntaxException {
+ return Uri.valueOfFilepath(IOUtil.slashify(file.getAbsolutePath(), true, file.isDirectory()));
+ }
+
+ /**
+ * Creates a new Uri instance using the given URI instance.
+ * <p>
+ * Re-encoding will be performed if the given URI is {@link URI#isOpaque() not opaque}.
+ * </p>
+ * <p>
+ * See {@link #PARSE_HINT_FIX_PATH} for issues of injecting opaque URLs.
+ * </p>
+ *
+ * @param uri A given URI instance
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri valueOf(final java.net.URI uri) throws URISyntaxException {
+ if( uri.isOpaque()) {
+ // opaque, without host validation.
+ // Note: This may induce encoding errors of authority and path, see {@link #PARSE_HINT_FIX_PATH}
+ return new Uri(new Encoded( uri.toString() ), false, 0);
+ } else if( null != uri.getHost() ) {
+ // with host validation
+ return Uri.create(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
+ uri.getPath(), uri.getQuery(), uri.getFragment());
+ } else {
+ // without host validation
+ return Uri.create(uri.getScheme(), uri.getAuthority(),
+ uri.getPath(), uri.getQuery(), uri.getFragment());
+ }
+ }
+
+ /**
+ * Creates a new Uri instance using the given URL instance,
+ * convenient wrapper for {@link #valueOf(URI)} and {@link URL#toURI()}.
+ * <p>
+ * Re-encoding will be performed if the given URL is {@link URI#isOpaque() not opaque}, see {@link #valueOf(URI)}.
+ * </p>
+ * <p>
+ * See {@link #PARSE_HINT_FIX_PATH} for issues of injecting opaque URLs.
+ * </p>
+ *
+ * @param url A given URL instance
+ *
+ * @throws URISyntaxException
+ * if the temporary created string doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ */
+ public static Uri valueOf(final java.net.URL url) throws URISyntaxException {
+ return valueOf(url.toURI());
+ }
+
+ //
+ // All string fields are encoded!
+ //
+
+ /** Encoded input string used at construction, never {@code null}. */
+ public final Encoded input;
+
+ private final Object lazyLock = new Object();
+
+ /** Encoded input string used at construction, in US-ASCII encoding. */
+ private ASCIIEncoded inputASCII;
+
+ private int hash;
+
+ /** Encoded {@code scheme}, {@code null} if undefined. */
+ public final Encoded scheme;
+
+ /** Encoded {@code scheme-specific-part}, never {@code null}. */
+ public final Encoded schemeSpecificPart;
+ /** Encoded {@code path} part of {@code scheme-specific-part}, never {@code null}. */
+ public final Encoded path;
+
+ /** Indicating whether {@code authority} part is defined or not. */
+ public final boolean hasAuthority;
+ /** Encoded {@code authority} part of {@code scheme-specific-part}, {@code null} if undefined. */
+ public final Encoded authority;
+ /** Encoded {@code userinfo} part of {@code authority} and {@code scheme-specific-part}, {@code null} if undefined. */
+ public final Encoded userInfo; // part of authority
+ /** Encoded {@code host} part of {@code authority} and {@code scheme-specific-part}, {@code null} if undefined. */
+ public final Encoded host; // part of authority
+ /** Encoded {@code port} part of {@code authority} and {@code scheme-specific-part}, {@code -1} if undefined. */
+ public final int port; // part of authority
+
+ /** Encoded {@code query} part of {@code scheme-specific-part}, {@code null} if undefined. */
+ public final Encoded query;
+
+ /** Encoded {@code fragment}, {@code null} if undefined. */
+ public final Encoded fragment;
+
+ /** Indicating whether this Uri is absolute, i.e. has a {@code scheme} and hence an absolute {@code scheme-specific-part}. */
+ public final boolean absolute;
+
+ /**
+ * Indicating whether this Uri is opaque, i.e. non-hierarchical {@code scheme-specific-part}.
+ * <p>
+ * An opaque Uri has no {@code scheme-specific-part} being parsed,
+ * i.e. {@code path}, {@code query} and {@code authority} are {@code null}.
+ * </p>
+ */
+ public final boolean opaque;
+
+ /**
+ * Creates a new Uri instance according to the given encoded string {@code uri}.
+ *
+ * @param uri the RFC3986 encoded RFC2396 Uri representation to be parsed into a Uri object
+ * @throws URISyntaxException
+ * if the given string {@code uri} doesn't fit to the
+ * specification RFC2396 and RFC3986 or could not be parsed correctly.
+ */
+ public Uri(final Encoded uri) throws URISyntaxException {
+ this(uri, false, 0);
+ }
+
+ /** Returns true, if this instance is a {@code file} {@code scheme}, otherwise false. */
+ public final boolean isFileScheme() {
+ return FILE_SCHEME.equals( scheme.get() );
+ }
+
+ /**
+ * Returns the encoded {@link #input}, never {@code null}.
+ */
+ public final Encoded getEncoded() {
+ return input;
+ }
+
+ /**
+ * Returns the encoded {@link #input} as String, never {@code null}, same as {@link #getEncoded()}.
+ */
+ @Override
+ public final String toString() {
+ return input.get();
+ }
+
+ /**
+ * Returns the encoded {@link #input} encoded in US-ASCII.
+ */
+ public ASCIIEncoded toASCIIString() {
+ synchronized( lazyLock ) {
+ if( null == inputASCII ) {
+ inputASCII = new ASCIIEncoded(input.get());
+ }
+ return inputASCII;
+ }
+ }
+
+ /**
+ * Returns a new {@link URI} instance using the encoded {@link #input} string, {@code new URI(uri.input)},
+ * i.e. no re-encoding will be performed.
+ * @see #toURIReencoded(boolean)
+ * @see #valueOf(URI)
+ */
+ public final java.net.URI toURI() {
+ try {
+ return new java.net.URI(input.get());
+ } catch (final URISyntaxException e) {
+ throw new Error(e); // Can't happen
+ }
+ }
+
+ /**
+ * Returns a new {@link URI} instance based upon this instance.
+ * <p>
+ * All Uri parts of this instance will be decoded
+ * and encoded by the URI constructor, i.e. re-encoding will be performed.
+ * </p>
+ *
+ * @throws URISyntaxException
+ * if the given string {@code uri} doesn't fit to the
+ * specification RFC2396 or could not be parsed correctly.
+ * @see #toURI()
+ * @see #valueOf(URI)
+ */
+ public final java.net.URI toURIReencoded() throws URISyntaxException {
+ final java.net.URI recomposedURI;
+ if( opaque ) {
+ // opaque, without host validation
+ recomposedURI = new java.net.URI(decode(scheme), decode(schemeSpecificPart), decode(fragment));
+ } else if( null != host ) {
+ // with host validation
+ recomposedURI = new java.net.URI(decode(scheme), decode(userInfo), decode(host), port,
+ decode(path), decode(query), decode(fragment));
+ } else {
+ // without host validation
+ recomposedURI = new java.net.URI(decode(scheme), decode(authority),
+ decode(path), decode(query), decode(fragment));
+ }
+ return recomposedURI;
+ }
+
+
+ /**
+ * Returns a new {@link URL} instance using the encoded {@link #input} string, {@code new URL(uri.input)},
+ * i.e. no re-encoding will be performed.
+ * @throws MalformedURLException
+ * if an error occurs while creating the URL or no protocol
+ * handler could be found.
+ */
+ public final java.net.URL toURL() throws MalformedURLException {
+ if (!absolute) {
+ throw new IllegalArgumentException("Cannot convert relative Uri: "+input);
+ }
+ return new java.net.URL(input.get());
+ }
+
+ /**
+ * If this instance {@link #isFileScheme() is a file scheme},
+ * implementation decodes <i>[ "//"+{@link #authority} ] + {@link #path}</i>,<br>
+ * then it processes the result if {@link File#separatorChar} <code> == '\\'</code>
+ * as follows:
+ * <ul>
+ * <li>slash -> backslash</li>
+ * <li>drop a starting single backslash, preserving windows UNC</li>
+ * </ul>
+ * and returns the resulting new {@link File} instance.
+ * <p>
+ * Otherwise implementation returns {@code null}.
+ * </p>
+ */
+ public final File toFile() {
+ if( isFileScheme() ) {
+ final String authorityS;
+ if( null == authority ) {
+ authorityS = "";
+ } else {
+ authorityS = "//"+authority.decode();
+ }
+ final String path = authorityS+this.path.decode();
+ if( File.separator.equals("\\") ) {
+ final String r = patternSingleFS.matcher(path).replaceAll("\\\\");
+ if( r.startsWith("\\") && !r.startsWith("\\\\") ) { // '\\\\' denotes UNC hostname, which shall not be cut-off
+ return new File(r.substring(1));
+ } else {
+ return new File(r);
+ }
+ }
+ return new File(path);
+ }
+ return null;
+ }
+
+ /**
+ * If this instance's {@link #schemeSpecificPart} contains a Uri itself, a sub-Uri,
+ * return {@link #schemeSpecificPart} + {@code #} {@link #fragment} via it's own new Uri instance.
+ * <p>
+ * In case this Uri is a {@code jar-scheme}, the {@code query} is omitted,
+ * since it shall be invalid for {@code jar-schemes} anyway.
+ * </p>
+ * <p>
+ * Otherwise method returns {@code null}.
+ * </p>
+ * <pre>
+ * Example 1:
+ * This instance: <code>jar:<i>scheme2</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+ * Returned Uri: <code><i>scheme2</i>:/some/path/gluegen-rt.jar</code>
+ *
+ * Example 2:
+ * This instance: <code>jar:<i>scheme2</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class?lala=01#fragment</code>
+ * Returned Uri: <code><i>scheme2</i>:/some/path/gluegen-rt.jar#fragment</code>
+ *
+ * Example 3:
+ * This instance: <code>scheme1:<i>scheme2</i>:/some/path/gluegen-rt.jar?lala=01#fragment</code>
+ * Returned Uri: <code><i>scheme2</i>:/some/path/gluegen-rt.jar?lala=01#fragment</code>
+ * </pre>
+ * @throws URISyntaxException
+ */
+ public final Uri getContainedUri() throws URISyntaxException {
+ if( !emptyString(schemeSpecificPart) ) {
+ final StringBuilder sb = new StringBuilder();
+
+ if( scheme.equals(JAR_SCHEME) ) {
+ final int idx = schemeSpecificPart.lastIndexOf(JAR_SCHEME_SEPARATOR);
+ if (0 > idx) {
+ throw new URISyntaxException(input.get(), "missing jar separator");
+ }
+ sb.append( schemeSpecificPart.get().substring(0, idx) ); // exclude '!/'
+ } else {
+ sb.append( schemeSpecificPart.get() );
+ }
+ if ( !emptyString(fragment) ) {
+ sb.append(FRAGMENT_SEPARATOR);
+ sb.append(fragment);
+ }
+ try {
+ final int parseHints = opaque ? PARSE_HINT_FIX_PATH : 0;
+ final Uri res = new Uri(new Encoded(sb.toString()), false, parseHints);
+ if( null != res.scheme ) {
+ return res;
+ }
+ } catch(final URISyntaxException e) {
+ // OK, does not contain uri
+ if( DEBUG ) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Return a new Uri instance representing the parent path of this Uri,
+ * while cutting of optional {@code query} and {@code fragment} parts.
+ * <p>
+ * Method is {@code jar-file-entry} aware, i.e. will return the parent entry if exists.
+ * </p>
+ * <p>
+ * If this Uri does not contain any path separator, or a parent folder Uri cannot be found, method returns {@code null}.
+ * </p>
+ * <pre>
+ * Example-1:
+ * This instance : <code>jar:http://some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+ * Returned Uri #1: <code>jar:http://some/path/gluegen-rt.jar!/com/jogamp/common/</code>
+ * Returned Uri #2: <code>jar:http://some/path/gluegen-rt.jar!/com/jogamp/</code>
+ *
+ * Example-2:
+ * This instance : <code>http://some/path/gluegen-rt.jar</code>
+ * Returned Uri #1: <code>http://some/path/</code>
+ * Returned Uri #2: <code>http://some/</code>
+ * </pre>
+ */
+ public final Uri getParent() {
+ final int pl = null!=schemeSpecificPart? schemeSpecificPart.length() : 0;
+ if(pl != 0) {
+ final int e = schemeSpecificPart.lastIndexOf("/");
+ if( e > 0 ) { // 0 == e: no path
+ if( e < pl - 1 ) {
+ // path is file or has a query
+ try {
+ return new Uri( new Encoded( scheme.get()+SCHEME_SEPARATOR+schemeSpecificPart.get().substring(0, e+1) ) );
+ } catch (final URISyntaxException ue) {
+ // not complete, hence removed authority, or even root folder -> return null
+ }
+ }
+ // path is a directory ..
+ final int p = schemeSpecificPart.lastIndexOf("/", e-1);
+ if( p > 0 ) {
+ try {
+ return new Uri( new Encoded( scheme.get()+SCHEME_SEPARATOR+schemeSpecificPart.get().substring(0, p+1) ) );
+ } catch (final URISyntaxException ue) {
+ // not complete, hence removed authority, or even root folder -> return null
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Concatenates the given encoded string to the {@link #getEncoded() encoded uri}
+ * of this instance and returns {@link #Uri(Encoded) a new Uri instance} with the result.
+ *
+ * @throws URISyntaxException
+ * if the concatenated string {@code uri} doesn't fit to the
+ * specification RFC2396 and RFC3986 or could not be parsed correctly.
+ */
+ public final Uri concat(final Uri.Encoded suffix) throws URISyntaxException {
+ if( null == suffix ) {
+ return this;
+ } else {
+ return new Uri( input.concat(suffix) );
+ }
+ }
+
+ /// NEW START
+
+ /**
+ * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code>
+ * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned,
+ * or {@code null} if not applicable.
+ * <p>
+ * <i>protocol</i> may be "file", "http", etc..
+ * </p>
+ *
+ * @return "<i>protocol</i>:/some/path/"
+ * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
+ * @throws URISyntaxException
+ */
+ public Uri getDirectory() throws URISyntaxException {
+ final String uriS = input.get();
+
+ // from
+ // file:/some/path/gluegen-rt.jar _or_ rsrc:gluegen-rt.jar
+ // to
+ // file:/some/path/ _or_ rsrc:
+ int idx = uriS.lastIndexOf('/');
+ if(0 > idx) {
+ // no abs-path, check for protocol terminator ':'
+ idx = uriS.lastIndexOf(':');
+ if(0 > idx) {
+ throw new URISyntaxException(input.get(), "no scheme terminator ':'");
+ }
+ }
+ try {
+ return Uri.cast(uriS.substring(0, idx+1)); // exclude jar name, include terminal '/' or ':'
+ } catch (final URISyntaxException ue) {
+ if( DEBUG ) {
+ ue.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Generates a URI for the <i>relativePath</i> relative to the <i>baseURI</i>,
+ * hence the result is a absolute location.
+ * <p>
+ * Impl. operates on the <i>scheme-specific-part</i>, and hence is sub-protocol savvy.
+ * </p>
+ * <p>
+ * In case <i>baseURI</i> is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used.
+ * </p>
+ *
+ * @param baseURI denotes a URI to a directory ending w/ '/', or a file. In the latter case the file's directory is being used.
+ * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
+ * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
+ */
+ public Uri getRelativeOf(final Encoded relativePath) throws URISyntaxException {
+ return compose(scheme, schemeSpecificPart, relativePath, fragment);
+ }
+
+ static Uri compose(final Encoded scheme, final Encoded schemeSpecificPart, final Encoded relativePath, final Encoded fragment) throws URISyntaxException {
+ String schemeSpecificPartS = schemeSpecificPart.get();
+
+ // cut off optional query in scheme-specific-part
+ final String query;
+ final int queryI = schemeSpecificPartS.lastIndexOf('?');
+ if( queryI >= 0 ) {
+ query = schemeSpecificPartS.substring(queryI+1);
+ schemeSpecificPartS = schemeSpecificPartS.substring(0, queryI);
+ } else {
+ query = null;
+ }
+ if( null != relativePath ) {
+ if( !schemeSpecificPartS.endsWith("/") ) {
+ schemeSpecificPartS = IOUtil.getParentOf(schemeSpecificPartS);
+ }
+ schemeSpecificPartS = schemeSpecificPartS + relativePath.get();
+ }
+ schemeSpecificPartS = IOUtil.cleanPathString( schemeSpecificPartS );
+ final StringBuilder uri = new StringBuilder();
+ uri.append(scheme.get());
+ uri.append(':');
+ uri.append(schemeSpecificPartS);
+ if ( null != query ) {
+ uri.append('?');
+ uri.append(query);
+ }
+ if ( null != fragment ) {
+ uri.append('#');
+ uri.append(fragment.get());
+ }
+ return Uri.cast(uri.toString());
+ }
+
+ /// NEW END
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Compares this Uri instance with the given argument {@code o} and
+ * determines if both are equal. Two Uri instances are equal if all single
+ * parts are identical in their meaning.
+ * </p>
+ *
+ * @param o
+ * the Uri this instance has to be compared with.
+ * @return {@code true} if both Uri instances point to the same resource,
+ * {@code false} otherwise.
+ */
+ @Override
+ public final boolean equals(final Object o) {
+ if (!(o instanceof Uri)) {
+ return false;
+ }
+ final Uri uri = (Uri) o;
+
+ if (uri.fragment == null && fragment != null || uri.fragment != null && fragment == null) {
+ return false;
+ } else if (uri.fragment != null && fragment != null) {
+ if (!equalsHexCaseInsensitive(uri.fragment, fragment)) {
+ return false;
+ }
+ }
+
+ if (uri.scheme == null && scheme != null || uri.scheme != null && scheme == null) {
+ return false;
+ } else if (uri.scheme != null && scheme != null) {
+ if (!uri.scheme.equalsIgnoreCase(scheme)) {
+ return false;
+ }
+ }
+
+ if (uri.opaque && opaque) {
+ return equalsHexCaseInsensitive(uri.schemeSpecificPart, schemeSpecificPart);
+ } else if (!uri.opaque && !opaque) {
+ if (!equalsHexCaseInsensitive(path, uri.path)) {
+ return false;
+ }
+
+ if (uri.query != null && query == null || uri.query == null && query != null) {
+ return false;
+ } else if (uri.query != null && query != null) {
+ if (!equalsHexCaseInsensitive(uri.query, query)) {
+ return false;
+ }
+ }
+
+ if (uri.authority != null && authority == null || uri.authority == null && authority != null) {
+ return false;
+ } else if (uri.authority != null && authority != null) {
+ if (uri.host != null && host == null || uri.host == null && host != null) {
+ return false;
+ } else if (uri.host == null && host == null) {
+ // both are registry based, so compare the whole authority
+ return equalsHexCaseInsensitive(uri.authority, authority);
+ } else { // uri.host != null && host != null, so server-based
+ if (!host.equalsIgnoreCase(uri.host)) {
+ return false;
+ }
+
+ if (port != uri.port) {
+ return false;
+ }
+
+ if ( uri.userInfo != null && userInfo == null ||
+ uri.userInfo == null && userInfo != null
+ ) {
+ return false;
+ } else if (uri.userInfo != null && userInfo != null) {
+ return equalsHexCaseInsensitive(userInfo, uri.userInfo);
+ } else {
+ return true;
+ }
+ }
+ } else {
+ // no authority
+ return true;
+ }
+
+ } else {
+ // one is opaque, the other hierarchical
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Gets the hashcode value of this Uri instance.
+ * </p>
+ */
+ @Override
+ public final int hashCode() {
+ synchronized( lazyLock ) {
+ if (hash == -1) {
+ hash = getHashString().hashCode();
+ }
+ return hash;
+ }
+ }
+
+ /*
+ * Takes a string that may contain hex sequences like %F1 or %2b and
+ * converts the hex values following the '%' to lowercase
+ */
+ private String convertHexToLowerCase(final String s) {
+ if (s.indexOf('%') == -1) {
+ return s;
+ }
+ final StringBuilder result = new StringBuilder("");
+ int index = 0, previndex = 0;
+ while ((index = s.indexOf('%', previndex)) != -1) {
+ result.append(s.substring(previndex, index + 1));
+ result.append(s.substring(index + 1, index + 3).toLowerCase());
+ index += 3;
+ previndex = index;
+ }
+ return result.toString();
+ }
+
+ /*
+ * Takes two strings that may contain hex sequences like %F1 or %2b and
+ * compares them, ignoring case for the hex values. Hex values must always
+ * occur in pairs as above
+ */
+ private boolean equalsHexCaseInsensitive(final Encoded first, final Encoded second) {
+ if (first.indexOf('%') != second.indexOf('%')) {
+ return first.equals(second);
+ }
+
+ int index = 0, previndex = 0;
+ while ( ( index = first.indexOf('%', previndex) ) != -1 &&
+ second.indexOf('%', previndex) == index
+ ) {
+ if( !first.get().substring(previndex, index).equals( second.get().substring(previndex, index) ) ) {
+ return false;
+ }
+ if( !first.get().substring(index + 1, index + 3).equalsIgnoreCase( second.get().substring(index + 1, index + 3) ) ) {
+ return false;
+ }
+ index += 3;
+ previndex = index;
+ }
+ return first.get().substring(previndex).equals( second.get().substring(previndex) );
+ }
+
+ /*
+ * Form a string from the components of this Uri, similarly to the
+ * toString() method. But this method converts scheme and host to lowercase,
+ * and converts escaped octets to lowercase.
+ */
+ private String getHashString() {
+ final StringBuilder result = new StringBuilder();
+ if (scheme != null) {
+ result.append(scheme.get().toLowerCase());
+ result.append(SCHEME_SEPARATOR);
+ }
+ if (opaque) {
+ result.append(schemeSpecificPart.get());
+ } else {
+ if (authority != null) {
+ result.append("//");
+ if (host == null) {
+ result.append(authority.get());
+ } else {
+ if (userInfo != null) {
+ result.append(userInfo.get() + "@");
+ }
+ result.append(host.get().toLowerCase());
+ if (port != -1) {
+ result.append(SCHEME_SEPARATOR + port);
+ }
+ }
+ }
+
+ if (path != null) {
+ result.append(path.get());
+ }
+
+ if (query != null) {
+ result.append('?');
+ result.append(query.get());
+ }
+ }
+
+ if (fragment != null) {
+ result.append(FRAGMENT_SEPARATOR);
+ result.append(fragment.get());
+ }
+ return convertHexToLowerCase(result.toString());
+ }
+
+ /**
+ *
+ * @param input
+ * @param expectServer
+ * @param parseHints TODO
+ * @throws URISyntaxException
+ */
+ private Uri(final Encoded input, final boolean expectServer, final int parseHints) throws URISyntaxException {
+ if( emptyString(input) ) {
+ throw new URISyntaxException(input.get(), "empty input");
+ }
+ String temp = input.get();
+ int index;
+ // parse into Fragment, Scheme, and SchemeSpecificPart
+ // then parse SchemeSpecificPart if necessary
+
+ // Fragment
+ index = temp.indexOf(FRAGMENT_SEPARATOR);
+ if (index != -1) {
+ // remove the fragment from the end
+ fragment = new Encoded( temp.substring(index + 1) );
+ validateFragment(input, fragment, index + 1);
+ temp = temp.substring(0, index);
+ } else {
+ fragment = null;
+ }
+
+ String inputTemp = input.get(); // may get modified due to error correction
+
+ // Scheme and SchemeSpecificPart
+ final int indexSchemeSep = temp.indexOf(SCHEME_SEPARATOR);
+ index = indexSchemeSep;
+ final int indexSSP = temp.indexOf('/');
+ final int indexQuerySep = temp.indexOf('?');
+
+ String sspTemp; // may get modified due to error correction
+
+ // if a '/' or '?' occurs before the first ':' the uri has no
+ // specified scheme, and is therefore not absolute
+ if ( indexSchemeSep != -1 &&
+ ( indexSSP >= indexSchemeSep || indexSSP == -1 ) &&
+ ( indexQuerySep >= indexSchemeSep || indexQuerySep == -1 )
+ ) {
+ // the characters up to the first ':' comprise the scheme
+ absolute = true;
+ scheme = new Encoded( temp.substring(0, indexSchemeSep) );
+ if (scheme.length() == 0) {
+ failExpecting(input, "scheme", indexSchemeSep);
+ }
+ validateScheme(input, scheme, 0);
+ sspTemp = temp.substring(indexSchemeSep + 1);
+ if (sspTemp.length() == 0) {
+ failExpecting(input, "scheme-specific-part", indexSchemeSep);
+ }
+ } else {
+ absolute = false;
+ scheme = null;
+ sspTemp = temp;
+ }
+
+ if ( scheme == null || sspTemp.length() > 0 && sspTemp.charAt(0) == '/' ) {
+ // Uri is hierarchical, not opaque
+ opaque = false;
+
+ // Query
+ temp = sspTemp;
+ index = temp.indexOf('?');
+ if (index != -1) {
+ query = new Encoded( temp.substring(index + 1) );
+ temp = temp.substring(0, index);
+ validateQuery(input, query, indexSSP + 1 + index);
+ } else {
+ query = null;
+ }
+
+ String pathTemp; // may get modified due to error correction
+ final int indexPathInSSP;
+
+ // Authority and Path
+ if (temp.startsWith("//")) {
+ index = temp.indexOf('/', 2);
+ final String authorityS;
+ if (index != -1) {
+ authorityS = temp.substring(2, index);
+ pathTemp = temp.substring(index);
+ indexPathInSSP = index;
+ } else {
+ authorityS = temp.substring(2);
+ if (authorityS.length() == 0 && query == null && fragment == null) {
+ failExpecting(input, "authority, path [, query, fragment]", index);
+ }
+ pathTemp = "";
+ indexPathInSSP = -1;
+ // nothing left, so path is empty
+ // (not null, path should never be null if hierarchical/non-opaque)
+ }
+ if ( emptyString(authorityS) ) {
+ authority = null;
+ } else {
+ authority = new Encoded( authorityS );
+ validateAuthority(input, authority, indexSchemeSep + 3);
+ }
+ } else { // no authority specified
+ pathTemp = temp;
+ indexPathInSSP = 0;
+ authority = null;
+ }
+
+ int indexPath = 0; // in input
+ if (indexSSP > -1) {
+ indexPath += indexSSP;
+ }
+ if (indexPathInSSP > -1) {
+ indexPath += indexPathInSSP;
+ }
+
+ final int pathErrIdx = validateEncoded(pathTemp, PATH_LEGAL);
+ if( 0 <= pathErrIdx ) {
+ // Perform error correction on PATH if requested!
+ if( 0 != ( parseHints & PARSE_HINT_FIX_PATH ) ) {
+ if( DEBUG_SHOWFIX ) {
+ System.err.println("Uri FIX_FILEPATH: input at index "+(indexPath+pathErrIdx)+": "+inputTemp);
+ System.err.println("Uri FIX_FILEPATH: ssp at index "+(indexPathInSSP+pathErrIdx)+": "+sspTemp);
+ System.err.println("Uri FIX_FILEPATH: path at index "+pathErrIdx+": "+pathTemp);
+ }
+ final int pathTempOldLen = pathTemp.length();
+ pathTemp = encode( decode( pathTemp ), PATH_LEGAL); // re-encode, and hope for the best!
+ validatePath(input, pathTemp, indexPath); // re-validate!
+ {
+ // Patch SSP + INPUT !
+ final StringBuilder sb = new StringBuilder();
+ if( indexPathInSSP > 0 ) {
+ sb.append( sspTemp.substring(0, indexPathInSSP) );
+ }
+ sb.append( pathTemp ).append( sspTemp.substring( indexPathInSSP + pathTempOldLen ) );
+ sspTemp = sb.toString(); // update
+
+ sb.setLength(0);
+ if( indexPath > 0 ) {
+ sb.append( inputTemp.substring(0, indexPath) );
+ }
+ sb.append( pathTemp ).append( inputTemp.substring( indexPath + pathTempOldLen ) );
+ inputTemp = sb.toString(); // update
+ }
+ if( DEBUG_SHOWFIX ) {
+ System.err.println("Uri FIX_FILEPATH: result : "+pathTemp);
+ System.err.println("Uri FIX_FILEPATH: ssp after : "+sspTemp);
+ System.err.println("Uri FIX_FILEPATH: input after : "+inputTemp);
+ }
+ } else {
+ fail(input, "invalid path", indexPath+pathErrIdx);
+ }
+ }
+ path = new Encoded( pathTemp );
+ } else {
+ // Uri is not hierarchical, Uri is opaque
+ opaque = true;
+ query = null;
+ path = null;
+ authority = null;
+ validateSsp(input, sspTemp, indexSchemeSep + 1);
+ }
+ schemeSpecificPart = new Encoded( sspTemp );
+ this.input = inputTemp == input.get() ? input : new Encoded( inputTemp );
+
+ /**
+ * determine the host, port and userinfo if the authority parses
+ * successfully to a server based authority
+ *
+ * Behavior in error cases: if forceServer is true, throw
+ * URISyntaxException with the proper diagnostic messages. if
+ * forceServer is false assume this is a registry based uri, and just
+ * return leaving the host, port and userinfo fields undefined.
+ *
+ * and there are some error cases where URISyntaxException is thrown
+ * regardless of the forceServer parameter e.g. malformed ipv6 address
+ */
+ Encoded tempUserinfo = null, tempHost = null;
+ int tempPort = -1;
+ boolean authorityComplete;
+
+ if ( null != authority ) {
+ authorityComplete = true; // set to false later
+ int hostindex = 0;
+
+ temp = authority.get();
+ index = temp.indexOf('@');
+ if (index != -1) {
+ // remove user info
+ tempUserinfo = new Encoded( temp.substring(0, index) );
+ validateUserinfo(authority, tempUserinfo, 0);
+ temp = temp.substring(index + 1); // host[:port] is left
+ hostindex = index + 1;
+ }
+
+ index = temp.lastIndexOf(SCHEME_SEPARATOR);
+ final int endindex = temp.indexOf(']');
+
+ if (index != -1 && endindex < index) {
+ // determine port and host
+ tempHost = new Encoded( temp.substring(0, index) );
+
+ if (index < (temp.length() - 1)) { // port part is not empty
+ try {
+ tempPort = Integer.parseInt(temp.substring(index + 1));
+ if (tempPort < 0) {
+ if (expectServer) {
+ fail(authority, "invalid port <"+authority+">", hostindex + index + 1);
+ }
+ authorityComplete = false;
+ }
+ } catch (final NumberFormatException e) {
+ if (expectServer) {
+ fail(authority, "invalid port <"+authority+">, "+e.getMessage(), hostindex + index + 1);
+ }
+ authorityComplete = false;
+ }
+ }
+ } else {
+ tempHost = new Encoded( temp );
+ }
+
+ if( authorityComplete ) {
+ if ( emptyString(tempHost) ) {
+ if (expectServer) {
+ fail(authority, "empty host <"+authority+">", hostindex);
+ }
+ authorityComplete = false;
+ } else if (!isValidHost(expectServer, tempHost)) {
+ if (expectServer) {
+ fail(authority, "invalid host <"+tempHost+">", hostindex);
+ }
+ authorityComplete = false;
+ }
+ }
+ } else {
+ authorityComplete = false;
+ }
+
+ if( authorityComplete ) {
+ // this is a server based uri,
+ // fill in the userinfo, host and port fields
+ userInfo = tempUserinfo;
+ host = tempHost;
+ port = tempPort;
+ hasAuthority = true;
+ } else {
+ userInfo = null;
+ host = null;
+ port = -1;
+ hasAuthority = false;
+ }
+ }
+
+ private static void validateScheme(final Encoded uri, final Encoded scheme, final int index) throws URISyntaxException {
+ // first char needs to be an alpha char
+ final char ch = scheme.charAt(0);
+ if ( !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) ) {
+ fail(uri, "invalid scheme", index);
+ }
+ final int errIdx = validateAlphaNum(scheme.get(), "+-.");
+ if( 0 <= errIdx ) {
+ fail(uri, "invalid scheme", index+errIdx);
+ }
+ }
+
+ private static void validateSsp(final Encoded uri, final String ssp, final int index) throws URISyntaxException {
+ final int errIdx = validateEncoded(ssp, SSP_LEGAL);
+ if( 0 <= errIdx ) {
+ fail(uri, "invalid scheme-specific-part", index+errIdx);
+ }
+ }
+
+ private static void validateAuthority(final Encoded uri, final Encoded authority, final int index) throws URISyntaxException {
+ final int errIdx = validateEncoded(authority.get(), AUTHORITY_LEGAL);
+ if( 0 <= errIdx ) {
+ fail(uri, "invalid authority", index+errIdx);
+ }
+ }
+
+ private static void validatePath(final Encoded uri, final String path, final int index) throws URISyntaxException {
+ final int errIdx = validateEncoded(path, PATH_LEGAL);
+ if( 0 <= errIdx ) {
+ fail(uri, "invalid path", index+errIdx);
+ }
+ }
+
+ private static void validateQuery(final Encoded uri, final Encoded query, final int index) throws URISyntaxException {
+ final int errIdx = validateEncoded(query.get(), QUERY_LEGAL);
+ if( 0 <= errIdx ) {
+ fail(uri, "invalid query", index+errIdx);
+ }
+ }
+
+ private static void validateFragment(final Encoded uri, final Encoded fragment, final int index) throws URISyntaxException {
+ final int errIdx = validateEncoded(fragment.get(), FRAG_LEGAL);
+ if( 0 <= errIdx ) {
+ fail(uri, "invalid fragment", index+errIdx);
+ }
+ }
+
+ private static void validateUserinfo(final Encoded uri, final Encoded userinfo, final int index) throws URISyntaxException {
+ for (int i = 0; i < userinfo.length(); i++) {
+ final char ch = userinfo.charAt(i);
+ if (ch == ']' || ch == '[') {
+ fail(uri, "invalid userinfo", index+i);
+ }
+ }
+ }
+
+ /**
+ * distinguish between IPv4, IPv6, domain name and validate it based on
+ * its type
+ */
+ private boolean isValidHost(final boolean expectServer, final Encoded host) throws URISyntaxException {
+ if (host.charAt(0) == '[') {
+ // ipv6 address
+ if (host.charAt(host.length() - 1) != ']') {
+ fail(input, "invalid host, missing closing ipv6: "+host, 0);
+ }
+ if (!isValidIP6Address(host.get())) {
+ fail(input, "invalid ipv6: "+host, 0);
+ }
+ return true;
+ }
+
+ // '[' and ']' can only be the first char and last char
+ // of the host name
+ if (host.indexOf('[') != -1 || host.indexOf(']') != -1) {
+ fail(input, "invalid host: "+host, 0);
+ }
+
+ final int index = host.lastIndexOf('.');
+ if ( index < 0 || index == host.length() - 1 ||
+ !Character.isDigit(host.charAt(index + 1)) )
+ {
+ // domain name
+ if (isValidDomainName(host)) {
+ return true;
+ }
+ if (expectServer) {
+ fail(input, "invalid host, invalid domain-name or ipv4: "+host, 0);
+ }
+ return false;
+ }
+
+ // IPv4 address
+ if (isValidIPv4Address(host.get())) {
+ return true;
+ }
+ if (expectServer) {
+ fail(input, "invalid host, invalid ipv4: "+host, 0);
+ }
+ return false;
+ }
+
+ private static boolean isValidDomainName(final Encoded host) {
+ final String hostS = host.get();
+ if( 0 <= validateAlphaNum(hostS, "-.") ) {
+ return false;
+ }
+ String label = null;
+ final StringTokenizer st = new StringTokenizer(hostS, ".");
+ while (st.hasMoreTokens()) {
+ label = st.nextToken();
+ if (label.startsWith("-") || label.endsWith("-")) {
+ return false;
+ }
+ }
+
+ if (!label.equals(hostS)) {
+ final char ch = label.charAt(0);
+ if (ch >= '0' && ch <= '9') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isValidIPv4Address(final String ipv4Address) {
+ int index;
+ int index2;
+ try {
+ int num;
+ index = ipv4Address.indexOf('.');
+ num = Integer.parseInt(ipv4Address.substring(0, index));
+ if (num < 0 || num > 255) {
+ return false;
+ }
+ index2 = ipv4Address.indexOf('.', index + 1);
+ num = Integer.parseInt(ipv4Address.substring(index + 1, index2));
+ if (num < 0 || num > 255) {
+ return false;
+ }
+ index = ipv4Address.indexOf('.', index2 + 1);
+ num = Integer.parseInt(ipv4Address.substring(index2 + 1, index));
+ if (num < 0 || num > 255) {
+ return false;
+ }
+ num = Integer.parseInt(ipv4Address.substring(index + 1));
+ if (num < 0 || num > 255) {
+ return false;
+ }
+ } catch (final Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isValidIP6Address(final String ipv6Address) {
+ final int length = ipv6Address.length();
+ boolean doubleColon = false;
+ int numberOfColons = 0;
+ int numberOfPeriods = 0;
+ String word = "";
+ char c = 0;
+ char prevChar = 0;
+ int offset = 0; // offset for [] ip addresses
+
+ if (length < 2) {
+ return false;
+ }
+
+ for (int i = 0; i < length; i++) {
+ prevChar = c;
+ c = ipv6Address.charAt(i);
+ switch (c) {
+
+ // case for an open bracket [x:x:x:...x]
+ case '[':
+ if (i != 0) {
+ return false; // must be first character
+ }
+ if (ipv6Address.charAt(length - 1) != ']') {
+ return false; // must have a close ]
+ }
+ if ((ipv6Address.charAt(1) == SCHEME_SEPARATOR)
+ && (ipv6Address.charAt(2) != SCHEME_SEPARATOR)) {
+ return false;
+ }
+ offset = 1;
+ if (length < 4) {
+ return false;
+ }
+ break;
+
+ // case for a closed bracket at end of IP [x:x:x:...x]
+ case ']':
+ if (i != length - 1) {
+ return false; // must be last character
+ }
+ if (ipv6Address.charAt(0) != '[') {
+ return false; // must have a open [
+ }
+ break;
+
+ // case for the last 32-bits represented as IPv4
+ // x:x:x:x:x:x:d.d.d.d
+ case '.':
+ numberOfPeriods++;
+ if (numberOfPeriods > 3) {
+ return false;
+ }
+ if (!isValidIP4Word(word)) {
+ return false;
+ }
+ if (numberOfColons != 6 && !doubleColon) {
+ return false;
+ }
+ // a special case ::1:2:3:4:5:d.d.d.d allows 7 colons
+ // with
+ // an IPv4 ending, otherwise 7 :'s is bad
+ if (numberOfColons == 7
+ && ipv6Address.charAt(0 + offset) != SCHEME_SEPARATOR
+ && ipv6Address.charAt(1 + offset) != SCHEME_SEPARATOR) {
+ return false;
+ }
+ word = "";
+ break;
+
+ case SCHEME_SEPARATOR:
+ numberOfColons++;
+ if (numberOfColons > 7) {
+ return false;
+ }
+ if (numberOfPeriods > 0) {
+ return false;
+ }
+ if (prevChar == SCHEME_SEPARATOR) {
+ if (doubleColon) {
+ return false;
+ }
+ doubleColon = true;
+ }
+ word = "";
+ break;
+
+ default:
+ if (word.length() > 3) {
+ return false;
+ }
+ if (!isValidHexChar(c)) {
+ return false;
+ }
+ word += c;
+ }
+ }
+
+ // Check if we have an IPv4 ending
+ if (numberOfPeriods > 0) {
+ if (numberOfPeriods != 3 || !isValidIP4Word(word)) {
+ return false;
+ }
+ } else {
+ // If we're at then end and we haven't had 7 colons then there
+ // is a problem unless we encountered a doubleColon
+ if (numberOfColons != 7 && !doubleColon) {
+ return false;
+ }
+
+ // If we have an empty word at the end, it means we ended in
+ // either a : or a .
+ // If we did not end in :: then this is invalid
+ if (word == "" && ipv6Address.charAt(length - 1 - offset) != SCHEME_SEPARATOR
+ && ipv6Address.charAt(length - 2 - offset) != SCHEME_SEPARATOR) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean isValidIP4Word(final String word) {
+ char c;
+ if (word.length() < 1 || word.length() > 3) {
+ return false;
+ }
+ for (int i = 0; i < word.length(); i++) {
+ c = word.charAt(i);
+ if (!(c >= '0' && c <= '9')) {
+ return false;
+ }
+ }
+ if (Integer.parseInt(word) > 255) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate a string by checking if it contains any characters other than:
+ * <ol>
+ * <li>letters ('a'..'z', 'A'..'Z')</li>
+ * <li>numbers ('0'..'9')</li>
+ * <li>characters in the legal-set parameter</li>
+ * <li> others (unicode characters that are not in
+ * US-ASCII set, and are not ISO Control or are not ISO Space characters)</li>
+ * </ol>
+ *
+ * @param encoded
+ * {@code java.lang.String} the string to be validated
+ * @param legal
+ * {@code java.lang.String} the characters allowed in the String
+ * s
+ */
+ private static int validateEncoded(final String encoded, final String legal) {
+ for (int i = 0; i < encoded.length();) {
+ final char ch = encoded.charAt(i);
+ if (ch == '%') {
+ do {
+ if (i + 2 >= encoded.length()) {
+ throw new IllegalArgumentException("missing '%' hex-digits at index "+i);
+ }
+ final int d1 = Character.digit(encoded.charAt(i + 1), 16);
+ final int d2 = Character.digit(encoded.charAt(i + 2), 16);
+ if (d1 == -1 || d2 == -1) {
+ throw new IllegalArgumentException("invalid hex-digits at index "+i+": "+encoded.substring(i, i + 3));
+ }
+ i += 3;
+ } while (i < encoded.length() && encoded.charAt(i) == '%');
+ continue;
+ }
+ if ( !( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1 ||
+ (ch > 127 && !Character.isSpaceChar(ch) && !Character.isISOControl(ch))
+ )
+ ) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+ private static int validateAlphaNum(final String s, final String legal) {
+ for (int i = 0; i < s.length();) {
+ final char ch = s.charAt(i);
+ if ( !( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1
+ )
+ ) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ private static boolean isValidHexChar(final char c) {
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+ }
+ private static boolean emptyString(final Encoded s) {
+ return null == s || 0 == s.length();
+ }
+ private static boolean emptyString(final String s) {
+ return null == s || 0 == s.length();
+ }
+
+ private static void fail(final Encoded input, final String reason, final int p) throws URISyntaxException {
+ throw new URISyntaxException(input.get(), reason, p);
+ }
+ private static void failExpecting(final Encoded input, final String expected, final int p) throws URISyntaxException {
+ fail(input, "Expecting " + expected, p);
+ }
+} \ No newline at end of file
diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java
index 12122a2..513d215 100644
--- a/src/java/com/jogamp/common/os/Platform.java
+++ b/src/java/com/jogamp/common/os/Platform.java
@@ -28,12 +28,12 @@
package com.jogamp.common.os;
-import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.TimeUnit;
import com.jogamp.common.jvm.JNILibLoaderBase;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.util.JarUtil;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.common.util.ReflectionUtil;
@@ -184,11 +184,11 @@ public class Platform extends PlatformPropsImpl {
final ClassLoader cl = Platform.class.getClassLoader();
- final URI platformClassJarURI;
+ final Uri platformClassJarURI;
{
- URI _platformClassJarURI = null;
+ Uri _platformClassJarURI = null;
try {
- _platformClassJarURI = JarUtil.getJarURI(Platform.class.getName(), cl);
+ _platformClassJarURI = JarUtil.getJarUri(Platform.class.getName(), cl);
} catch (final Exception e) { }
platformClassJarURI = _platformClassJarURI;
}
diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java
index 5819fbc..3a09835 100644
--- a/src/java/com/jogamp/common/util/IOUtil.java
+++ b/src/java/com/jogamp/common/util/IOUtil.java
@@ -40,7 +40,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
-import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
@@ -52,6 +51,7 @@ import jogamp.common.os.AndroidUtils;
import jogamp.common.os.PlatformPropsImpl;
import com.jogamp.common.net.AssetURLContext;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.os.MachineDescription;
import com.jogamp.common.os.Platform;
@@ -59,19 +59,6 @@ import com.jogamp.common.os.Platform;
public class IOUtil {
public static final boolean DEBUG = Debug.debug("IOUtil");
- /** {@value} */
- public static final String SCHEME_SEPARATOR = ":";
- /** {@value} */
- public static final String FILE_SCHEME = "file";
- /** {@value} */
- public static final String HTTP_SCHEME = "http";
- /** {@value} */
- public static final String HTTPS_SCHEME = "https";
- /** {@value} */
- public static final String JAR_SCHEME = "jar";
- /** A JAR subprotocol is separeted from the JAR entry w/ this separator {@value}. Even if no class is specified '!/' must follow!. */
- public static final char JAR_SCHEME_SEPARATOR = '!';
-
/** Std. temporary directory property key <code>java.io.tmpdir</code>. */
private static final String java_io_tmpdir_propkey = "java.io.tmpdir";
private static final String user_home_propkey = "user.home";
@@ -289,6 +276,8 @@ public class IOUtil {
*
*/
+ private static final Pattern patternSingleBS = Pattern.compile("\\\\{1}");
+
/**
*
* @param path
@@ -298,7 +287,7 @@ public class IOUtil {
* @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
*/
public static String slashify(final String path, final boolean startWithSlash, final boolean endWithSlash) throws URISyntaxException {
- String p = path.replace('\\', '/'); // unify file separator
+ String p = patternSingleBS.matcher(path).replaceAll("/");
if (startWithSlash && !p.startsWith("/")) {
p = "/" + p;
}
@@ -309,24 +298,6 @@ public class IOUtil {
}
/**
- * Using the simple conversion via File -> URI, assuming proper characters.
- * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
- * @throws URISyntaxException if the resulting string does not comply w/ an RFC 2396 URI
- */
- public static URI toURISimple(final File file) throws URISyntaxException {
- return new URI(FILE_SCHEME, null, slashify(file.getAbsolutePath(), true /* startWithSlash */, file.isDirectory() /* endWithSlash */), null);
- }
-
- /**
- * Using the simple conversion via File -> URI, assuming proper characters.
- * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
- * @throws URISyntaxException if the resulting string does not comply w/ an RFC 2396 URI
- */
- public static URI toURISimple(final String protocol, final String path, final boolean isDirectory) throws URISyntaxException {
- return new URI(protocol, null, slashify(new File(path).getAbsolutePath(), true /* startWithSlash */, isDirectory /* endWithSlash */), null);
- }
-
- /**
* Returns the lowercase suffix of the given file name (the text
* after the last '.' in the file name). Returns null if the file
* name has no suffix. Only operates on the given file name;
@@ -434,79 +405,6 @@ public class IOUtil {
return fname;
}
- /**
- * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code>
- * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned.
- * <p>
- * <i>protocol</i> may be "file", "http", etc..
- * </p>
- *
- * @param uri "<i>protocol</i>:/some/path/gluegen-rt.jar"
- * @return "<i>protocol</i>:/some/path/"
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
- * @throws URISyntaxException
- */
- public static URI getURIDirname(final URI uri) throws IllegalArgumentException, URISyntaxException {
- if(null == uri) {
- throw new IllegalArgumentException("URI is null");
- }
- final String uriS = uri.toString();
- if( DEBUG ) {
- System.err.println("getURIDirname "+uri+", extForm: "+uriS);
- }
- return new URI( getURIDirname(uriS) );
- }
-
- /**
- * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code>
- * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned.
- * <p>
- * <i>protocol</i> may be "file", "http", etc..
- * </p>
- *
- * @param uri "<i>protocol</i>:/some/path/gluegen-rt.jar" (URI encoded)
- * @return "<i>protocol</i>:/some/path/"
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
- * @throws URISyntaxException
- */
- public static String getURIDirname(String uriS) throws IllegalArgumentException, URISyntaxException {
- if(null == uriS) {
- throw new IllegalArgumentException("uriS is null");
- }
- // from
- // file:/some/path/gluegen-rt.jar _or_ rsrc:gluegen-rt.jar
- // to
- // file:/some/path/ _or_ rsrc:
- int idx = uriS.lastIndexOf('/');
- if(0 > idx) {
- // no abs-path, check for protocol terminator ':'
- idx = uriS.lastIndexOf(':');
- if(0 > idx) {
- throw new IllegalArgumentException("URI does not contain protocol terminator ':', in <"+uriS+">");
- }
- }
- uriS = uriS.substring(0, idx+1); // exclude jar name, include terminal '/' or ':'
-
- if( DEBUG ) {
- System.err.println("getJarURIDirname res: "+uriS);
- }
- return uriS;
- }
-
- /**
- * Simply returns {@link URI#toURL()}.
- * @param uri
- * @return
- * @throws IOException
- * @throws IllegalArgumentException
- * @throws URISyntaxException
- *
- * @deprecated Useless
- */
- public static URL toURL(final URI uri) throws IOException, IllegalArgumentException, URISyntaxException {
- return uri.toURL();
- }
-
/***
*
* RESOURCE LOCATION STUFF
@@ -638,6 +536,20 @@ public class IOUtil {
}
/**
+ * Wraps {@link #getRelativeOf(URI, String)} for convenience.
+ * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
+ * @throws IOException
+ * @deprecated Use {@link Uri#getRelativeOf(com.jogamp.common.net.Uri.Encoded)}.
+ */
+ public static URL getRelativeOf(final URL baseURL, final String relativePath) throws IOException {
+ try {
+ return Uri.valueOf(baseURL).getRelativeOf(Uri.Encoded.cast(relativePath)).toURL();
+ } catch (final URISyntaxException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
* Generates a path for the 'relativeFile' relative to the 'baseLocation'.
*
* @param baseLocation denotes a directory
@@ -705,177 +617,7 @@ public class IOUtil {
return path;
}
- /**
- * Generates a URI for the <i>relativePath</i> relative to the <i>baseURI</i>,
- * hence the result is a absolute location.
- * <p>
- * Impl. operates on the <i>scheme-specific-part</i>, and hence is sub-protocol savvy.
- * </p>
- * <p>
- * In case <i>baseURI</i> is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used.
- * </p>
- *
- * @param baseURI denotes a URI to a directory ending w/ '/', or a file. In the latter case the file's directory is being used.
- * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
- * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
- */
- public static URI getRelativeOf(final URI baseURI, final String relativePath) throws URISyntaxException {
- return compose(baseURI.getScheme(), baseURI.getRawSchemeSpecificPart(), relativePath, baseURI.getRawFragment());
- }
-
- /**
- * Wraps {@link #getRelativeOf(URI, String)} for convenience.
- * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
- * @throws IOException
- */
- public static URL getRelativeOf(final URL baseURL, final String relativePath) throws IOException {
- try {
- return getRelativeOf(baseURL.toURI(), relativePath).toURL();
- } catch (final URISyntaxException e) {
- throw new IOException(e);
- }
- }
-
- /**
- * Generates a URI for the <i>relativePath</i> relative to the <i>schemeSpecificPart</i>,
- * hence the result is a absolute location.
- * <p>
- * <i>schemeSpecificPart</i>'s query, if exist is split to <i>path</i> and <i>query</i>.
- * </p>
- * <p>
- * In case <i>path</i> is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used.
- * </p>
- *
- * @param scheme scheme of the resulting URI
- * @param schemeSpecificPart may include a query, which is separated while processing (URI encoded)
- * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
- * @param fragment the URI fragment (URI encoded)
- * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
- * @see #encodeToURI(String)
- */
- public static URI compose(final String scheme, String schemeSpecificPart, final String relativePath, final String fragment) throws URISyntaxException {
- // cut off optional query in scheme-specific-part
- final String query;
- final int queryI = schemeSpecificPart.lastIndexOf('?');
- if( queryI >= 0 ) {
- query = schemeSpecificPart.substring(queryI+1);
- schemeSpecificPart = schemeSpecificPart.substring(0, queryI);
- } else {
- query = null;
- }
- if( null != relativePath ) {
- if( !schemeSpecificPart.endsWith("/") ) {
- schemeSpecificPart = getParentOf(schemeSpecificPart);
- }
- schemeSpecificPart = schemeSpecificPart + relativePath;
- }
- schemeSpecificPart = cleanPathString( schemeSpecificPart );
- final StringBuilder uri = new StringBuilder();
- uri.append(scheme);
- uri.append(':');
- uri.append(schemeSpecificPart);
- if ( null != query ) {
- uri.append('?');
- uri.append(query);
- }
- if ( null != fragment ) {
- uri.append('#');
- uri.append(fragment);
- }
- return new URI(uri.toString());
- }
-
- private static final Pattern patternSpaceRaw = Pattern.compile(" ");
- private static final Pattern patternSpaceEnc = Pattern.compile("%20");
-
- /**
- * Escapes characters not complying w/ RFC 2396 and the {@link URI#URI(String)} ctor.
- * <ul>
- * <li>SPACE -> %20</li>
- * </ul>
- * @deprecated Useless
- */
- public static String encodeToURI(final String vanilla) {
- return patternSpaceRaw.matcher(vanilla).replaceAll("%20"); // Uri TODO: Uri.encode(vanilla, Uri.PATH_MIN_LEGAL);
- }
-
- /**
- * Reverses escaping of characters as performed via {@link #encodeToURI(String)}.
- * <ul>
- * <li>%20 -> SPACE</li>
- * </ul>
- * @deprecated Use {@link #decodeURIIfFilePath(URI)}
- */
- public static String decodeFromURI(final String encodedUri) {
- return patternSpaceEnc.matcher(encodedUri).replaceAll(" "); // Uri TODO: Uri.decode(encoded);
- }
-
- private static final Pattern patternSingleBS = Pattern.compile("\\\\{1}");
- private static final Pattern patternSingleFS = Pattern.compile("/{1}");
-
- /**
- * Encodes file path characters not complying w/ RFC 2396 and the {@link URI#URI(String)} ctor.
- * <p>
- * Implementation processes the <code>filePath</code> if {@link File#separatorChar} <code> == '\\'</code>
- * as follows:
- * <ul>
- * <li>backslash -> slash</li>
- * <li>ensure starting with slash</li>
- * </ul>
- * </p>
- * <p>
- * Note that this method does not perform <i>space</i> encoding,
- * which can be utilized via {@link #encodeToURI(String)}.
- * </p>
- * <p>
- * Even though Oracle's JarURLStreamHandler can handle backslashes and
- * erroneous URIs w/ e.g. Windows file 'syntax', other may not (Netbeans).<br>
- * See Bug 857 - http://jogamp.org/bugzilla/show_bug.cgi?id=857
- * </p>
- * @see #encodeToURI(String)
- * @deprecated Useless
- */
- public static String encodeFilePathToURI(final String filePath) {
- if( File.separator.equals("\\") ) {
- final String r = patternSingleBS.matcher(filePath).replaceAll("/");
- if( !r.startsWith("/") ) {
- return "/" + r;
- } else {
- return r;
- }
- }
- return filePath;
- }
-
- /**
- * Completes decoding uri-file path characters complying w/ RFC 2396 to native file-path.
- * <p>
- * Implementation decodes the space-encoding <code>path={@link #decodeFromURI(String) decodeFromURI}(uriPath)</code>.
- * </p>
- * <p>
- * Then it processes the <code>path</code> if {@link File#separatorChar} <code> == '\\'</code>
- * as follows:
- * <ul>
- * <li>slash -> backslash</li>
- * <li>drop a starting single backslash, preserving windows UNC</li>
- * </ul>
- * </p>
- * @param encodedUriPath URI encoded path
- * @see #decodeFromURI(String)
- * @deprecated Use {@link #decodeURIIfFilePath(URI)}
- */
- public static String decodeURIToFilePath(final String encodedUriPath) {
- final String path = patternSpaceEnc.matcher(encodedUriPath).replaceAll(" "); // Uri TODO: Uri.decode(encoded);
- if( File.separator.equals("\\") ) {
- final String r = patternSingleFS.matcher(path).replaceAll("\\\\");
- if( r.startsWith("\\") && !r.startsWith("\\\\") ) { // '\\\\' denotes UNC hostname, which shall not be cut-off
- return r.substring(1);
- } else {
- return r;
- }
- }
- return path;
- }
+ public static final Pattern patternSpaceEnc = Pattern.compile("%20");
/**
* If <code>uri</code> is a <i>file scheme</i>,
@@ -890,33 +632,19 @@ public class IOUtil {
* <p>
* Otherwise it returns the {@link URI#toASCIIString()} encoded URI.
* </p>
- *
- * @see #decodeFromURI(String)
- * @see #decodeURIToFilePath(String)
+ * @deprecated Use {@link Uri#toFile()}
*/
- public static String decodeURIIfFilePath(final URI uri) {
- if( IOUtil.FILE_SCHEME.equals( uri.getScheme() ) ) {
- final String authorityS;
- {
- final String authority = uri.getAuthority();
- if( null == authority ) {
- authorityS = "";
- } else {
- authorityS = "//"+authority;
- }
- final String path = patternSpaceEnc.matcher(authorityS+uri.getPath()).replaceAll(" "); // Uri TODO: Uri.decode(encoded);
- if( File.separator.equals("\\") ) {
- final String r = patternSingleFS.matcher(path).replaceAll("\\\\");
- if( r.startsWith("\\") && !r.startsWith("\\\\") ) { // '\\\\' denotes UNC hostname, which shall not be cut-off
- return r.substring(1);
- } else {
- return r;
- }
- }
- return path;
+ public static String decodeURIIfFilePath(final java.net.URI uri) {
+ try {
+ final File file = Uri.valueOf(uri).toFile();
+ if( null != file ) {
+ return file.getPath();
+ } else {
+ return uri.toASCIIString();
}
+ } catch (final URISyntaxException e) {
+ throw new RuntimeException(e);
}
- return uri.toASCIIString();
}
/**
diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java
index 3fe03bf..745dd12 100644
--- a/src/java/com/jogamp/common/util/JarUtil.java
+++ b/src/java/com/jogamp/common/util/JarUtil.java
@@ -35,7 +35,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
-import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
@@ -46,6 +45,7 @@ import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.os.NativeLibrary;
import com.jogamp.common.os.Platform;
@@ -111,18 +111,18 @@ public class JarUtil {
* @param clazzBinName "com.jogamp.common.GlueGenVersion"
* @param cl
* @return true if the class is loaded from a Jar file, otherwise false.
- * @see {@link #getJarURI(String, ClassLoader)}
+ * @see {@link #getJarUri(String, ClassLoader)}
*/
- public static boolean hasJarURI(final String clazzBinName, final ClassLoader cl) {
+ public static boolean hasJarUri(final String clazzBinName, final ClassLoader cl) {
try {
- return null != getJarURI(clazzBinName, cl);
+ return null != getJarUri(clazzBinName, cl);
} catch (final Exception e) { /* ignore */ }
return false;
}
/**
* The Class's <code>"com.jogamp.common.GlueGenVersion"</code>
- * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
+ * Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
* will be returned.
* <p>
* <i>sub_protocol</i> may be "file", "http", etc..
@@ -131,108 +131,107 @@ public class JarUtil {
* @param clazzBinName "com.jogamp.common.GlueGenVersion"
* @param cl ClassLoader to locate the JarFile
* @return "jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting or null arguments
+ * @throws IllegalArgumentException if the Uri doesn't match the expected formatting or null arguments
* @throws IOException if the class's Jar file could not been found by the ClassLoader
- * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
+ * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
* @see {@link IOUtil#getClassURL(String, ClassLoader)}
*/
- public static URI getJarURI(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
+ public static Uri getJarUri(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
if(null == clazzBinName || null == cl) {
throw new IllegalArgumentException("null arguments: clazzBinName "+clazzBinName+", cl "+cl);
}
- final URI uri;
+ final Uri uri;
final URL url;
{
url = IOUtil.getClassURL(clazzBinName, cl);
final String scheme = url.getProtocol();
if( null != resolver &&
- !scheme.equals( IOUtil.JAR_SCHEME ) &&
- !scheme.equals( IOUtil.FILE_SCHEME ) &&
- !scheme.equals( IOUtil.HTTP_SCHEME ) &&
- !scheme.equals( IOUtil.HTTPS_SCHEME ) )
+ !scheme.equals( Uri.JAR_SCHEME ) &&
+ !scheme.equals( Uri.FILE_SCHEME ) &&
+ !scheme.equals( Uri.HTTP_SCHEME ) &&
+ !scheme.equals( Uri.HTTPS_SCHEME ) )
{
final URL _url = resolver.resolve( url );
- uri = _url.toURI();
+ uri = Uri.valueOf(_url);
if(DEBUG) {
- System.err.println("getJarURI Resolver: "+url+"\n\t-> "+_url+"\n\t-> "+uri);
+ System.err.println("getJarUri Resolver: "+url+"\n\t-> "+_url+"\n\t-> "+uri);
}
} else {
- uri = url.toURI();
+ uri = Uri.valueOf(url);
if(DEBUG) {
- System.err.println("getJarURI Default "+url+"\n\t-> "+uri);
+ System.err.println("getJarUri Default "+url+"\n\t-> "+uri);
}
}
}
- // test name ..
- if( !uri.getScheme().equals( IOUtil.JAR_SCHEME ) ) {
- throw new IllegalArgumentException("URI is not using scheme "+IOUtil.JAR_SCHEME+": <"+uri+">");
+ if( !uri.scheme.equals( Uri.JAR_SCHEME ) ) {
+ throw new IllegalArgumentException("Uri is not using scheme "+Uri.JAR_SCHEME+": <"+uri+">");
}
if(DEBUG) {
- System.err.println("getJarURI res: "+clazzBinName+" -> "+url+" -> "+uri);
+ System.err.println("getJarUri res: "+clazzBinName+" -> "+url+" -> "+uri);
}
return uri;
}
/**
- * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+ * The Class's Jar Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
* Jar basename <code>gluegen-rt.jar</code> will be returned.
* <p>
* <i>sub_protocol</i> may be "file", "http", etc..
* </p>
*
- * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()},
+ * @param classJarUri as retrieved w/ {@link #getJarUri(String, ClassLoader) getJarUri("com.jogamp.common.GlueGenVersion", cl)},
* i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
* @return <code>gluegen-rt.jar</code>
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting or is null
+ * @throws IllegalArgumentException if the Uri doesn't match the expected formatting or is null
* @see {@link IOUtil#getClassURL(String, ClassLoader)}
*/
- public static String getJarBasename(final URI classJarURI) throws IllegalArgumentException {
- if(null == classJarURI) {
- throw new IllegalArgumentException("URI is null");
+ public static Uri.Encoded getJarBasename(final Uri classJarUri) throws IllegalArgumentException {
+ if(null == classJarUri) {
+ throw new IllegalArgumentException("Uri is null");
}
- if( !classJarURI.getScheme().equals(IOUtil.JAR_SCHEME) ) {
- throw new IllegalArgumentException("URI is not using scheme "+IOUtil.JAR_SCHEME+": <"+classJarURI+">");
+ if( !classJarUri.scheme.equals(Uri.JAR_SCHEME) ) {
+ throw new IllegalArgumentException("Uri is not using scheme "+Uri.JAR_SCHEME+": <"+classJarUri+">");
}
- String uriS = classJarURI.getSchemeSpecificPart();
+ Uri.Encoded ssp = classJarUri.schemeSpecificPart;
// from
// file:/some/path/gluegen-rt.jar!/com/jogamp/common/util/cache/TempJarCache.class
// to
// file:/some/path/gluegen-rt.jar
- int idx = uriS.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR);
+ int idx = ssp.lastIndexOf(Uri.JAR_SCHEME_SEPARATOR);
if (0 <= idx) {
- uriS = uriS.substring(0, idx); // exclude '!/'
+ ssp = ssp.substring(0, idx); // exclude '!/'
} else {
- throw new IllegalArgumentException("URI does not contain jar uri terminator '!', in <"+classJarURI+">");
+ throw new IllegalArgumentException("Uri does not contain jar uri terminator '!', in <"+classJarUri+">");
}
// from
// file:/some/path/gluegen-rt.jar
// to
// gluegen-rt.jar
- idx = uriS.lastIndexOf('/');
+ idx = ssp.lastIndexOf('/');
if(0 > idx) {
// no abs-path, check for protocol terminator ':'
- idx = uriS.lastIndexOf(':');
+ idx = ssp.lastIndexOf(':');
if(0 > idx) {
- throw new IllegalArgumentException("URI does not contain protocol terminator ':', in <"+classJarURI+">");
+ throw new IllegalArgumentException("Uri does not contain protocol terminator ':', in <"+classJarUri+">");
}
}
- uriS = uriS.substring(idx+1); // just the jar name
+ ssp = ssp.substring(idx+1); // just the jar name
- if(0 >= uriS.lastIndexOf(".jar")) {
- throw new IllegalArgumentException("No Jar name in <"+classJarURI+">");
+ if(0 >= ssp.lastIndexOf(".jar")) {
+ throw new IllegalArgumentException("No Jar name in <"+classJarUri+">");
}
if(DEBUG) {
- System.err.println("getJarName res: "+uriS);
+ System.err.println("getJarName res: "+ssp);
}
- return uriS;
+ return ssp;
}
/**
* The Class's <code>com.jogamp.common.GlueGenVersion</code>
- * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+ * Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
* Jar basename <code>gluegen-rt.jar</code> will be returned.
* <p>
* <i>sub_protocol</i> may be "file", "http", etc..
@@ -241,119 +240,54 @@ public class JarUtil {
* @param clazzBinName <code>com.jogamp.common.GlueGenVersion</code>
* @param cl
* @return <code>gluegen-rt.jar</code>
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting
+ * @throws IllegalArgumentException if the Uri doesn't match the expected formatting
* @throws IOException if the class's Jar file could not been found by the ClassLoader.
- * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
+ * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
* @see {@link IOUtil#getClassURL(String, ClassLoader)}
*/
- public static String getJarBasename(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
- return getJarBasename( getJarURI(clazzBinName, cl) );
+ public static Uri.Encoded getJarBasename(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
+ return getJarBasename( getJarUri(clazzBinName, cl) );
}
/**
- * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
- * Jar file's sub URI <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code> will be returned.
- * <p>
- * <i>sub_protocol</i> may be "file", "http", etc..
- * </p>
- *
- * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()},
- * i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
- * @return <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code>
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting or is null
- * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
- * @see {@link IOUtil#getClassURL(String, ClassLoader)}
- */
- public static URI getJarSubURI(final URI classJarURI) throws IllegalArgumentException, URISyntaxException {
- if(null == classJarURI) {
- throw new IllegalArgumentException("URI is null");
- }
- if( !classJarURI.getScheme().equals(IOUtil.JAR_SCHEME) ) {
- throw new IllegalArgumentException("URI is not a using scheme "+IOUtil.JAR_SCHEME+": <"+classJarURI+">");
- }
-
- // from
- // file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
- // to
- // file:/some/path/gluegen-rt.jar
- final String uriSSP = classJarURI.getRawSchemeSpecificPart();
- final int idx = uriSSP.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR);
- final String uriSSPJar;
- if (0 <= idx) {
- uriSSPJar = uriSSP.substring(0, idx); // exclude '!/'
- } else {
- throw new IllegalArgumentException("JAR URI does not contain jar uri terminator '!', uri <"+classJarURI+">");
- }
- if(0 >= uriSSPJar.lastIndexOf(".jar")) {
- throw new IllegalArgumentException("No Jar name in <"+classJarURI+">");
- }
- if(DEBUG) {
- System.err.println("getJarSubURI res: "+classJarURI+" -> "+uriSSP+" -> "+uriSSPJar);
- }
- return new URI(uriSSPJar);
- }
-
- /**
- * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+ * The Class's Jar Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
* Jar file's entry <code>/com/jogamp/common/GlueGenVersion.class</code> will be returned.
*
- * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()},
+ * @param classJarUri as retrieved w/ {@link #getJarUri(String, ClassLoader) getJarUri("com.jogamp.common.GlueGenVersion", cl)},
* i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
* @return <code>/com/jogamp/common/GlueGenVersion.class</code>
* @see {@link IOUtil#getClassURL(String, ClassLoader)}
- * @deprecated Useless
*/
- public static String getJarEntry(final URI classJarURI) {
- if(null == classJarURI) {
- throw new IllegalArgumentException("URI is null");
+ public static Uri.Encoded getJarEntry(final Uri classJarUri) {
+ if(null == classJarUri) {
+ throw new IllegalArgumentException("Uri is null");
}
- if( !classJarURI.getScheme().equals(IOUtil.JAR_SCHEME) ) {
- throw new IllegalArgumentException("URI is not a using scheme "+IOUtil.JAR_SCHEME+": <"+classJarURI+">");
+ if( !classJarUri.scheme.equals(Uri.JAR_SCHEME) ) {
+ throw new IllegalArgumentException("Uri is not a using scheme "+Uri.JAR_SCHEME+": <"+classJarUri+">");
}
- final String uriSSP = classJarURI.getSchemeSpecificPart();
- // Uri TODO ? final String uriSSP = classJarURI.getRawSchemeSpecificPart();
+ final Uri.Encoded uriSSP = classJarUri.schemeSpecificPart;
// from
// file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
// to
// /com/jogamp/common/GlueGenVersion.class
- final int idx = uriSSP.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR);
+ final int idx = uriSSP.lastIndexOf(Uri.JAR_SCHEME_SEPARATOR);
if (0 <= idx) {
- final String res = uriSSP.substring(idx+1); // right of '!'
+ final Uri.Encoded res = uriSSP.substring(idx+1); // right of '!'
// Uri TODO ? final String res = Uri.decode(uriSSP.substring(idx+1)); // right of '!'
if(DEBUG) {
- System.err.println("getJarEntry res: "+classJarURI+" -> "+uriSSP+" -> "+idx+" -> "+res);
+ System.err.println("getJarEntry res: "+classJarUri+" -> "+uriSSP+" -> "+idx+" -> "+res);
}
return res;
} else {
- throw new IllegalArgumentException("JAR URI does not contain jar uri terminator '!', uri <"+classJarURI+">");
+ throw new IllegalArgumentException("JAR Uri does not contain jar uri terminator '!', uri <"+classJarUri+">");
}
}
/**
- * The Class's <code>com.jogamp.common.GlueGenVersion</code>
- * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
- * Jar file's sub URI <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code> will be returned.
- * <p>
- * <i>sub_protocol</i> may be "file", "http", etc..
- * </p>
- *
- * @param clazzBinName <code>com.jogamp.common.GlueGenVersion</code>
- * @param cl
- * @return <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code>
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting
- * @throws IOException if the class's Jar file could not been found by the ClassLoader
- * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
- * @see {@link IOUtil#getClassURL(String, ClassLoader)}
- */
- public static URI getJarSubURI(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
- return getJarSubURI( getJarURI(clazzBinName, cl) );
- }
-
- /**
* The Class's <code>"com.jogamp.common.GlueGenVersion"</code>
- * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
- * Jar file URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/</code> will be returned.
+ * Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
+ * Jar file Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/</code> will be returned.
* <p>
* <i>sub_protocol</i> may be "file", "http", etc..
* </p>
@@ -361,34 +295,35 @@ public class JarUtil {
* @param clazzBinName "com.jogamp.common.GlueGenVersion"
* @param cl
* @return "jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/"
- * @throws IllegalArgumentException if the URI doesn't match the expected formatting or null arguments
+ * @throws IllegalArgumentException if the Uri doesn't match the expected formatting or null arguments
* @throws IOException if the class's Jar file could not been found by the ClassLoader
- * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
+ * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
* @see {@link IOUtil#getClassURL(String, ClassLoader)}
*/
- public static URI getJarFileURI(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
+ public static Uri getJarFileUri(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
if(null == clazzBinName || null == cl) {
throw new IllegalArgumentException("null arguments: clazzBinName "+clazzBinName+", cl "+cl);
}
- final URI uri = new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+getJarSubURI(clazzBinName, cl).toString()+"!/");
+ final Uri jarSubUri = getJarUri(clazzBinName, cl).getContainedUri();
+ final Uri uri = Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+jarSubUri.toString()+"!/");
if(DEBUG) {
- System.err.println("getJarFileURI res: "+uri);
+ System.err.println("getJarFileUri res: "+uri);
}
return uri;
}
/**
* @param baseUri file:/some/path/
- * @param jarFileName gluegen-rt.jar (URI encoded)
+ * @param jarFileName gluegen-rt.jar (Uri encoded)
* @return jar:file:/some/path/gluegen-rt.jar!/
* @throws URISyntaxException
* @throws IllegalArgumentException null arguments
*/
- public static URI getJarFileURI(final URI baseUri, final String jarFileName) throws IllegalArgumentException, URISyntaxException {
+ public static Uri getJarFileUri(final Uri baseUri, final Uri.Encoded jarFileName) throws IllegalArgumentException, URISyntaxException {
if(null == baseUri || null == jarFileName) {
- throw new IllegalArgumentException("null arguments: baseURI "+baseUri+", jarFileName "+jarFileName);
+ throw new IllegalArgumentException("null arguments: baseUri "+baseUri+", jarFileName "+jarFileName);
}
- return new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+baseUri.toString()+jarFileName+"!/");
+ return Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+baseUri.toString()+jarFileName+"!/");
}
/**
@@ -397,38 +332,38 @@ public class JarUtil {
* @throws IllegalArgumentException null arguments
* @throws URISyntaxException
*/
- public static URI getJarFileURI(final URI jarSubUri) throws IllegalArgumentException, URISyntaxException {
+ public static Uri getJarFileUri(final Uri jarSubUri) throws IllegalArgumentException, URISyntaxException {
if(null == jarSubUri) {
- throw new IllegalArgumentException("jarSubURI is null");
+ throw new IllegalArgumentException("jarSubUri is null");
}
- return new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+jarSubUri.toString()+"!/");
+ return Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+jarSubUri.toString()+"!/");
}
/**
- * @param jarSubUriS file:/some/path/gluegen-rt.jar (URI encoded)
+ * @param jarSubUriS file:/some/path/gluegen-rt.jar (Uri encoded)
* @return jar:file:/some/path/gluegen-rt.jar!/
* @throws IllegalArgumentException null arguments
* @throws URISyntaxException
*/
- public static URI getJarFileURI(final String jarSubUriS) throws IllegalArgumentException, URISyntaxException {
+ public static Uri getJarFileUri(final Uri.Encoded jarSubUriS) throws IllegalArgumentException, URISyntaxException {
if(null == jarSubUriS) {
- throw new IllegalArgumentException("jarSubURIS is null");
+ throw new IllegalArgumentException("jarSubUriS is null");
}
- return new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+jarSubUriS+"!/");
+ return Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+jarSubUriS+"!/");
}
/**
- * @param jarFileURI jar:file:/some/path/gluegen-rt.jar!/
+ * @param jarFileUri jar:file:/some/path/gluegen-rt.jar!/
* @param jarEntry com/jogamp/common/GlueGenVersion.class
* @return jar:file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
* @throws IllegalArgumentException null arguments
* @throws URISyntaxException
*/
- public static URI getJarEntryURI(final URI jarFileURI, final String jarEntry) throws IllegalArgumentException, URISyntaxException {
+ public static Uri getJarEntryUri(final Uri jarFileUri, final Uri.Encoded jarEntry) throws IllegalArgumentException, URISyntaxException {
if(null == jarEntry) {
throw new IllegalArgumentException("jarEntry is null");
}
- return new URI(jarFileURI.toString()+jarEntry);
+ return Uri.cast(jarFileUri.toString()+jarEntry);
}
/**
@@ -437,28 +372,28 @@ public class JarUtil {
* @return JarFile containing the named class within the given ClassLoader
* @throws IOException if the class's Jar file could not been found by the ClassLoader
* @throws IllegalArgumentException null arguments
- * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
- * @see {@link #getJarFileURI(String, ClassLoader)}
+ * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
+ * @see {@link #getJarFileUri(String, ClassLoader)}
*/
public static JarFile getJarFile(final String clazzBinName, final ClassLoader cl) throws IOException, IllegalArgumentException, URISyntaxException {
- return getJarFile( getJarFileURI(clazzBinName, cl) );
+ return getJarFile( getJarFileUri(clazzBinName, cl) );
}
/**
- * @param jarFileURI jar:file:/some/path/gluegen-rt.jar!/
- * @return JarFile as named by URI within the given ClassLoader
+ * @param jarFileUri jar:file:/some/path/gluegen-rt.jar!/
+ * @return JarFile as named by Uri within the given ClassLoader
* @throws IllegalArgumentException null arguments
* @throws IOException if the Jar file could not been found
* @throws URISyntaxException
*/
- public static JarFile getJarFile(final URI jarFileURI) throws IOException, IllegalArgumentException, URISyntaxException {
- if(null == jarFileURI) {
- throw new IllegalArgumentException("null jarFileURI");
+ public static JarFile getJarFile(final Uri jarFileUri) throws IOException, IllegalArgumentException, URISyntaxException {
+ if(null == jarFileUri) {
+ throw new IllegalArgumentException("null jarFileUri");
}
if(DEBUG) {
- System.err.println("getJarFile.0: "+jarFileURI.toString());
+ System.err.println("getJarFile.0: "+jarFileUri.toString());
}
- final URL jarFileURL = jarFileURI.toURL();
+ final URL jarFileURL = jarFileUri.toURL();
if(DEBUG) {
System.err.println("getJarFile.1: "+jarFileURL.toString());
}
@@ -478,8 +413,22 @@ public class JarUtil {
}
/**
- * Locates the {@link JarUtil#getJarFileURI(URI) Jar file URI} of a given resource
- * relative to a given class's Jar's URI.
+ * See {@link #getRelativeOf(Class, com.jogamp.common.net.Uri.Encoded, com.jogamp.common.net.Uri.Encoded)}.
+ * @param classFromJavaJar URI encoded!
+ * @param cutOffInclSubDir URI encoded!
+ * @param relResPath URI encoded!
+ * @return
+ * @throws IllegalArgumentException
+ * @throws IOException
+ * @throws URISyntaxException
+ * @deprecated Use {@link #getRelativeOf(Class, com.jogamp.common.net.Uri.Encoded, com.jogamp.common.net.Uri.Encoded)}.
+ */
+ public static java.net.URI getRelativeOf(final Class<?> classFromJavaJar, final String cutOffInclSubDir, final String relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
+ return getRelativeOf(classFromJavaJar, Uri.Encoded.cast(cutOffInclSubDir), Uri.Encoded.cast(relResPath)).toURI();
+ }
+ /**
+ * Locates the {@link JarUtil#getJarFileUri(Uri) Jar file Uri} of a given resource
+ * relative to a given class's Jar's Uri.
* <pre>
* class's jar url path + cutOffInclSubDir + relResPath,
* </pre>
@@ -500,47 +449,47 @@ public class JarUtil {
*
* TODO: Enhance documentation!
*
- * @param classFromJavaJar Used to get the root URI for the class's Jar URI.
+ * @param classFromJavaJar Used to get the root Uri for the class's Jar Uri.
* @param cutOffInclSubDir The <i>cut off</i> included sub-directory prepending the relative resource path.
- * If the root URI includes cutOffInclSubDir, it is no more added to the result.
- * @param relResPath The relative resource path. (URI encoded)
- * @return The resulting resource URI, which is not tested.
+ * If the root Uri includes cutOffInclSubDir, it is no more added to the result.
+ * @param relResPath The relative resource path. (Uri encoded)
+ * @return The resulting resource Uri, which is not tested.
* @throws IllegalArgumentException
* @throws IOException
* @throws URISyntaxException
*/
- public static URI getRelativeOf(final Class<?> classFromJavaJar, final String cutOffInclSubDir, final String relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
+ public static Uri getRelativeOf(final Class<?> classFromJavaJar, final Uri.Encoded cutOffInclSubDir, final Uri.Encoded relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
final ClassLoader cl = classFromJavaJar.getClassLoader();
- final URI classJarURI = JarUtil.getJarURI(classFromJavaJar.getName(), cl);
+ final Uri classJarUri = JarUtil.getJarUri(classFromJavaJar.getName(), cl);
if( DEBUG ) {
- System.err.println("JarUtil.getRelativeOf: "+"(classFromJavaJar "+classFromJavaJar+", classJarURI "+classJarURI+
+ System.err.println("JarUtil.getRelativeOf: "+"(classFromJavaJar "+classFromJavaJar+", classJarUri "+classJarUri+
", cutOffInclSubDir "+cutOffInclSubDir+", relResPath "+relResPath+"): ");
}
- final URI jarSubURI = JarUtil.getJarSubURI( classJarURI );
- if(null == jarSubURI) {
- throw new IllegalArgumentException("JarSubURI is null of: "+classJarURI);
+ final Uri jarSubUri = classJarUri.getContainedUri();
+ if(null == jarSubUri) {
+ throw new IllegalArgumentException("JarSubUri is null of: "+classJarUri);
}
- final String jarUriRoot_s = IOUtil.getURIDirname( jarSubURI.toString() );
+ final Uri.Encoded jarUriRoot = jarSubUri.getDirectory().getEncoded();
if( DEBUG ) {
- System.err.println("JarUtil.getRelativeOf: "+"uri "+jarSubURI.toString()+" -> "+jarUriRoot_s);
+ System.err.println("JarUtil.getRelativeOf: "+"uri "+jarSubUri.toString()+" -> "+jarUriRoot);
}
- final String resUri_s;
- if( jarUriRoot_s.endsWith(cutOffInclSubDir) ) {
- resUri_s = jarUriRoot_s+relResPath;
+ final Uri.Encoded resUri;
+ if( jarUriRoot.endsWith(cutOffInclSubDir.get()) ) {
+ resUri = jarUriRoot.concat(relResPath);
} else {
- resUri_s = jarUriRoot_s+cutOffInclSubDir+relResPath;
+ resUri = jarUriRoot.concat(cutOffInclSubDir).concat(relResPath);
}
if( DEBUG ) {
- System.err.println("JarUtil.getRelativeOf: "+"... -> "+resUri_s);
+ System.err.println("JarUtil.getRelativeOf: "+"... -> "+resUri);
}
- final URI resURI = JarUtil.getJarFileURI(resUri_s);
+ final Uri resJarUri = JarUtil.getJarFileUri(resUri);
if( DEBUG ) {
- System.err.println("JarUtil.getRelativeOf: "+"fin "+resURI);
+ System.err.println("JarUtil.getRelativeOf: "+"fin "+resJarUri);
}
- return resURI;
+ return resJarUri;
}
/**
diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java
index 1b322d7..05d92e1 100644
--- a/src/java/com/jogamp/common/util/cache/TempJarCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java
@@ -29,7 +29,6 @@ package com.jogamp.common.util.cache;
import java.io.File;
import java.io.IOException;
-import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.Certificate;
import java.util.HashMap;
@@ -38,8 +37,8 @@ import java.util.jar.JarFile;
import jogamp.common.Debug;
+import com.jogamp.common.net.Uri;
import com.jogamp.common.os.NativeLibrary;
-import com.jogamp.common.util.IOUtil;
import com.jogamp.common.util.JarUtil;
import com.jogamp.common.util.SecurityUtil;
@@ -68,9 +67,9 @@ public class TempJarCache {
}
// Set of jar files added
- private static Map<URI, LoadState> nativeLibJars;
- private static Map<URI, LoadState> classFileJars;
- private static Map<URI, LoadState> resourceFileJars;
+ private static Map<Uri, LoadState> nativeLibJars;
+ private static Map<Uri, LoadState> classFileJars;
+ private static Map<Uri, LoadState> resourceFileJars;
private static TempFileCache tmpFileCache;
@@ -96,9 +95,9 @@ public class TempJarCache {
if(!staticInitError) {
// Initialize the collections of resources
nativeLibMap = new HashMap<String, String>();
- nativeLibJars = new HashMap<URI, LoadState>();
- classFileJars = new HashMap<URI, LoadState>();
- resourceFileJars = new HashMap<URI, LoadState>();
+ nativeLibJars = new HashMap<Uri, LoadState>();
+ classFileJars = new HashMap<Uri, LoadState>();
+ resourceFileJars = new HashMap<Uri, LoadState>();
}
if(DEBUG) {
System.err.println("TempJarCache.initSingleton(): ok "+(false==staticInitError)+", "+ tmpFileCache.getTempDir());
@@ -182,62 +181,62 @@ public class TempJarCache {
return tmpFileCache;
}
- public synchronized static boolean checkNativeLibs(final URI jarURI, final LoadState exp) throws IOException {
+ public synchronized static boolean checkNativeLibs(final Uri jarUri, final LoadState exp) throws IOException {
checkInitialized();
- if(null == jarURI) {
- throw new IllegalArgumentException("jarURI is null");
+ if(null == jarUri) {
+ throw new IllegalArgumentException("jarUri is null");
}
- return testLoadState(nativeLibJars.get(jarURI), exp);
+ return testLoadState(nativeLibJars.get(jarUri), exp);
}
- public synchronized static boolean checkClasses(final URI jarURI, final LoadState exp) throws IOException {
+ public synchronized static boolean checkClasses(final Uri jarUri, final LoadState exp) throws IOException {
checkInitialized();
- if(null == jarURI) {
- throw new IllegalArgumentException("jarURI is null");
+ if(null == jarUri) {
+ throw new IllegalArgumentException("jarUri is null");
}
- return testLoadState(classFileJars.get(jarURI), exp);
+ return testLoadState(classFileJars.get(jarUri), exp);
}
- public synchronized static boolean checkResources(final URI jarURI, final LoadState exp) throws IOException {
+ public synchronized static boolean checkResources(final Uri jarUri, final LoadState exp) throws IOException {
checkInitialized();
- if(null == jarURI) {
- throw new IllegalArgumentException("jarURI is null");
+ if(null == jarUri) {
+ throw new IllegalArgumentException("jarUri is null");
}
- return testLoadState(resourceFileJars.get(jarURI), exp);
+ return testLoadState(resourceFileJars.get(jarUri), exp);
}
/**
* Adds native libraries, if not yet added.
*
* @param certClass if class is certified, the JarFile entries needs to have the same certificate
- * @param jarURI
+ * @param jarUri
* @param nativeLibraryPath if not null, only extracts native libraries within this path.
- * @return true if native libraries were added or previously loaded from given jarURI, otherwise false
- * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+ * @return true if native libraries were added or previously loaded from given jarUri, otherwise false
+ * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
* @throws SecurityException
* @throws URISyntaxException
* @throws IllegalArgumentException
*/
- public synchronized static final boolean addNativeLibs(final Class<?> certClass, final URI jarURI, final String nativeLibraryPath) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+ public synchronized static final boolean addNativeLibs(final Class<?> certClass, final Uri jarUri, final String nativeLibraryPath) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
checkInitialized();
- final LoadState nativeLibJarsLS = nativeLibJars.get(jarURI);
+ final LoadState nativeLibJarsLS = nativeLibJars.get(jarUri);
if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ) {
- nativeLibJars.put(jarURI, LoadState.LOOKED_UP);
- final JarFile jarFile = JarUtil.getJarFile(jarURI);
+ nativeLibJars.put(jarUri, LoadState.LOOKED_UP);
+ final JarFile jarFile = JarUtil.getJarFile(jarUri);
if(DEBUG) {
- System.err.println("TempJarCache: addNativeLibs: "+jarURI+": nativeJar "+jarFile.getName()+" (NEW)");
+ System.err.println("TempJarCache: addNativeLibs: "+jarUri+": nativeJar "+jarFile.getName()+" (NEW)");
}
validateCertificates(certClass, jarFile);
final int num = JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile, nativeLibraryPath, true, false, false);
- nativeLibJars.put(jarURI, LoadState.LOADED);
+ nativeLibJars.put(jarUri, LoadState.LOADED);
return num > 0;
} else if( testLoadState(nativeLibJarsLS, LoadState.LOADED) ) {
if(DEBUG) {
- System.err.println("TempJarCache: addNativeLibs: "+jarURI+": nativeJar "+jarURI+" (REUSE)");
+ System.err.println("TempJarCache: addNativeLibs: "+jarUri+": nativeJar "+jarUri+" (REUSE)");
}
return true;
}
- throw new IOException("TempJarCache: addNativeLibs: "+jarURI+", previous load attempt failed");
+ throw new IOException("TempJarCache: addNativeLibs: "+jarUri+", previous load attempt failed");
}
/**
@@ -247,56 +246,69 @@ public class TempJarCache {
* needs Classloader.defineClass(..) access, ie. own derivation - will do when needed ..
*
* @param certClass if class is certified, the JarFile entries needs to have the same certificate
- * @param jarURI
- * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+ * @param jarUri
+ * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
* @throws SecurityException
* @throws URISyntaxException
* @throws IllegalArgumentException
*/
- public synchronized static final void addClasses(final Class<?> certClass, final URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+ public synchronized static final void addClasses(final Class<?> certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
checkInitialized();
- final LoadState classFileJarsLS = classFileJars.get(jarURI);
+ final LoadState classFileJarsLS = classFileJars.get(jarUri);
if( !testLoadState(classFileJarsLS, LoadState.LOOKED_UP) ) {
- classFileJars.put(jarURI, LoadState.LOOKED_UP);
- final JarFile jarFile = JarUtil.getJarFile(jarURI);
+ classFileJars.put(jarUri, LoadState.LOOKED_UP);
+ final JarFile jarFile = JarUtil.getJarFile(jarUri);
if(DEBUG) {
- System.err.println("TempJarCache: addClasses: "+jarURI+": nativeJar "+jarFile.getName());
+ System.err.println("TempJarCache: addClasses: "+jarUri+": nativeJar "+jarFile.getName());
}
validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile,
null /* nativeLibraryPath */, false, true, false);
- classFileJars.put(jarURI, LoadState.LOADED);
+ classFileJars.put(jarUri, LoadState.LOADED);
} else if( !testLoadState(classFileJarsLS, LoadState.LOADED) ) {
- throw new IOException("TempJarCache: addClasses: "+jarURI+", previous load attempt failed");
+ throw new IOException("TempJarCache: addClasses: "+jarUri+", previous load attempt failed");
}
}
/**
+ * See {@link #addResources(Class, Uri)}
+ * @param certClass
+ * @param jarURI
+ * @throws IOException
+ * @throws SecurityException
+ * @throws IllegalArgumentException
+ * @throws URISyntaxException
+ * @deprecated Use {@link #addResources(Class, Uri)}
+ */
+ public synchronized static final void addResources(final Class<?> certClass, final java.net.URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+ addResources(certClass, Uri.valueOf(jarURI));
+ }
+ /**
* Adds native resources, if not yet added.
*
* @param certClass if class is certified, the JarFile entries needs to have the same certificate
- * @param jarURI
+ * @param jarUri
* @return
- * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+ * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
* @throws SecurityException
* @throws URISyntaxException
* @throws IllegalArgumentException
*/
- public synchronized static final void addResources(final Class<?> certClass, final URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+ public synchronized static final void addResources(final Class<?> certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
checkInitialized();
- final LoadState resourceFileJarsLS = resourceFileJars.get(jarURI);
+ final LoadState resourceFileJarsLS = resourceFileJars.get(jarUri);
if( !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) {
- resourceFileJars.put(jarURI, LoadState.LOOKED_UP);
- final JarFile jarFile = JarUtil.getJarFile(jarURI);
+ resourceFileJars.put(jarUri, LoadState.LOOKED_UP);
+ final JarFile jarFile = JarUtil.getJarFile(jarUri);
if(DEBUG) {
- System.err.println("TempJarCache: addResources: "+jarURI+": nativeJar "+jarFile.getName());
+ System.err.println("TempJarCache: addResources: "+jarUri+": nativeJar "+jarFile.getName());
}
validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile,
null /* nativeLibraryPath */, false, false, true);
- resourceFileJars.put(jarURI, LoadState.LOADED);
+ resourceFileJars.put(jarUri, LoadState.LOADED);
} else if( !testLoadState(resourceFileJarsLS, LoadState.LOADED) ) {
- throw new IOException("TempJarCache: addResources: "+jarURI+", previous load attempt failed");
+ throw new IOException("TempJarCache: addResources: "+jarUri+", previous load attempt failed");
}
}
@@ -308,20 +320,20 @@ public class TempJarCache {
* needs Classloader.defineClass(..) access, ie. own derivation - will do when needed ..
*
* @param certClass if class is certified, the JarFile entries needs to have the same certificate
- * @param jarURI
- * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+ * @param jarUri
+ * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
* @throws SecurityException
* @throws URISyntaxException
* @throws IllegalArgumentException
*/
- public synchronized static final void addAll(final Class<?> certClass, final URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+ public synchronized static final void addAll(final Class<?> certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
checkInitialized();
- if(null == jarURI) {
- throw new IllegalArgumentException("jarURI is null");
+ if(null == jarUri) {
+ throw new IllegalArgumentException("jarUri is null");
}
- final LoadState nativeLibJarsLS = nativeLibJars.get(jarURI);
- final LoadState classFileJarsLS = classFileJars.get(jarURI);
- final LoadState resourceFileJarsLS = resourceFileJars.get(jarURI);
+ final LoadState nativeLibJarsLS = nativeLibJars.get(jarUri);
+ final LoadState classFileJarsLS = classFileJars.get(jarUri);
+ final LoadState resourceFileJarsLS = resourceFileJars.get(jarUri);
if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ||
!testLoadState(classFileJarsLS, LoadState.LOOKED_UP) ||
!testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) {
@@ -332,18 +344,18 @@ public class TempJarCache {
// mark looked-up (those who are not loaded)
if(extractNativeLibraries) {
- nativeLibJars.put(jarURI, LoadState.LOOKED_UP);
+ nativeLibJars.put(jarUri, LoadState.LOOKED_UP);
}
if(extractClassFiles) {
- classFileJars.put(jarURI, LoadState.LOOKED_UP);
+ classFileJars.put(jarUri, LoadState.LOOKED_UP);
}
if(extractOtherFiles) {
- resourceFileJars.put(jarURI, LoadState.LOOKED_UP);
+ resourceFileJars.put(jarUri, LoadState.LOOKED_UP);
}
- final JarFile jarFile = JarUtil.getJarFile(jarURI);
+ final JarFile jarFile = JarUtil.getJarFile(jarUri);
if(DEBUG) {
- System.err.println("TempJarCache: addAll: "+jarURI+": nativeJar "+jarFile.getName());
+ System.err.println("TempJarCache: addAll: "+jarUri+": nativeJar "+jarFile.getName());
}
validateCertificates(certClass, jarFile);
JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile,
@@ -351,18 +363,18 @@ public class TempJarCache {
// mark loaded (those were just loaded)
if(extractNativeLibraries) {
- nativeLibJars.put(jarURI, LoadState.LOADED);
+ nativeLibJars.put(jarUri, LoadState.LOADED);
}
if(extractClassFiles) {
- classFileJars.put(jarURI, LoadState.LOADED);
+ classFileJars.put(jarUri, LoadState.LOADED);
}
if(extractOtherFiles) {
- resourceFileJars.put(jarURI, LoadState.LOADED);
+ resourceFileJars.put(jarUri, LoadState.LOADED);
}
} else if( !testLoadState(nativeLibJarsLS, LoadState.LOADED) ||
!testLoadState(classFileJarsLS, LoadState.LOADED) ||
!testLoadState(resourceFileJarsLS, LoadState.LOADED) ) {
- throw new IOException("TempJarCache: addAll: "+jarURI+", previous load attempt failed");
+ throw new IOException("TempJarCache: addAll: "+jarUri+", previous load attempt failed");
}
}
@@ -407,12 +419,20 @@ public class TempJarCache {
return null;
}
+ /**
+ * See {@link #getResourceUri(String)}
+ * @deprecated Use {@link #getResourceUri(String)}
+ */
+ public synchronized static final java.net.URI getResource(final String name) throws URISyntaxException {
+ return getResourceUri(name).toURI();
+ }
+
/** Similar to {@link ClassLoader#getResource(String)}. */
- public synchronized static final URI getResource(final String name) throws URISyntaxException {
+ public synchronized static final Uri getResourceUri(final String name) throws URISyntaxException {
checkInitialized();
final File f = new File(tmpFileCache.getTempDir(), name);
if(f.exists()) {
- return IOUtil.toURISimple(f);
+ return Uri.valueOf(f);
}
return null;
}