From 5205e47e8a2e84e793b26305391b1c4f8648597c Mon Sep 17 00:00:00 2001
From: Sven Gothel
+ * Character encoding is employed as defined by RFC 3986,
+ * see RFC 3986 section 2.1,
+ * while multibyte unicode characters are preserved in encoded parts.
+ *
+ * RFC 3986 section 2.2 Reserved Characters (January 2005)
+ *
+ 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]
+ *
+ *
+
+ *
+
+ *
+ !
+ *
+ '
+ (
+ )
+ ;
+ :
+ @
+ &
+ =
+ +
+ $
+ ,
+ /
+ ?
+ #
+ [
+ ]
+ * RFC 3986 section 2.3 Unreserved Characters (January 2005) + *
A |
+ B |
+ C |
+ D |
+ E |
+ F |
+ G |
+ H |
+ I |
+ J |
+ K |
+ L |
+ M |
+ N |
+ O |
+ P |
+ Q |
+ R |
+ S |
+ T |
+ U |
+ V |
+ W |
+ X |
+ Y |
+ Z |
+
a |
+ b |
+ c |
+ d |
+ e |
+ f |
+ g |
+ h |
+ i |
+ j |
+ k |
+ l |
+ m |
+ n |
+ o |
+ p |
+ q |
+ r |
+ s |
+ t |
+ u |
+ v |
+ w |
+ x |
+ y |
+ z |
+
0 |
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ 6 |
+ 7 |
+ 8 |
+ 9 |
+ - |
+ _ |
+ . |
+ ~ |
+
+ * Other characters in a Uri must be percent encoded. + *
+ * @since 2.2.1 + */ +public class Uri { + 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) + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String UNRESERVED = "_-.~"; // Harmony: "_-!.~\'()*" + + private static final String punct = ",;:$&+="; + + /** + * RFC 3986 section 2.2 Reserved Characters (January 2005) + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String RESERVED = punct + "!*\'()@/?#[]"; // Harmony: punct + "?/[]@"; + + public static final String RESERVED_2 = punct + "!*\'()@/?[]"; // Harmony: punct + "?/[]@"; + + // Bug 908, issues w/ windows file path char: $ ^ ~ # [ ] + + /** + * Valid charset for RFC 2396 {@code authority}'s {@code user-info}, + * additional to legal {@code alphanum} characters. + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String USERINFO_LEGAL = UNRESERVED + punct; + + /** + * Valid charset for RFC 2396 {@code authority}, + * additional to legal {@code alphanum} characters. + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String AUTHORITY_LEGAL = "@[]" + USERINFO_LEGAL; + + /** + * Valid charset for RFC 2396 {@code path}, + * additional to legal {@code alphanum} characters. + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String PATH_LEGAL = "/!" + USERINFO_LEGAL; + // @ is reserved; Harmony: "/@" + SOME_LEGAL, '!' is re-added, Harmony had it in UNRESERVED + + /** + * Reduced valid charset for RFC 2396 {@code path}, + * additional to legal {@code alphanum} characters. + *+ * Excluding special native filesystem characters to be encoded. + *
+ *+ * {@value} + {@code alphanum} + *
+ */ + public static final String PATH_MIN_LEGAL = "/!_-."; // "/!" + ( unreserved - '~' ) + + /** + * Valid charset for RFC 2396 {@code query}, + * additional to legal {@code alphanum} characters. + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String QUERY_LEGAL = UNRESERVED + RESERVED_2 + "\\\""; + + /** + * Valid charset for RFC 2396 {@code scheme-specific-part}, + * additional to legal {@code alphanum} characters. + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String SSP_LEGAL = QUERY_LEGAL; + + /** + * Valid charset for RFC 2396 {@code fragment}, + * additional to legal {@code alphanum} characters. + *+ * {@value} + {@code alphanum} + *
+ */ + public static final String FRAG_LEGAL = UNRESERVED + RESERVED; + + /** + * Immutable RFC3986 encoded string. + */ + public static class Encoded implements Comparable+ * No encoding will be performed, use with care. + *
+ */ + 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: + *+ * Uses {@link Uri#encode(String, String)} for implementation.. + *
+ * + * @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; } + + 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. + *+ *'%' and two following hex digit characters are converted to the + * equivalent byte value. All other characters are passed through + * unmodified. + *
+ *+ * e.g. "A%20B%20C %24%25" -> "A B C $%" + *
+ *+ * Uses {@link Uri#decode(String)} for implementation.. + *
+ */ + public final String decode() { return Uri.decode(s); } + + // + // Basic Object / Identity + // + + @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 String substring(final int start) { return s.substring(start); } + /** See {@link String#substring(int, int)}. */ + public final String substring(final int start, final int end) { return 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#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. + *+ * No encoding will be performed, use with care. + *
+ */ + 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 '%'. + *+ * For example: Euro currency symbol -> "%E2%82%AC". + *
+ *+ * Uses {@link Uri#encodeToASCIIString(String)} for implementation. + *
+ * @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: + *+ * Use {@link #encodeToASCIIString(String)} for US-ASCII encoding. + *
+ *+ * Consider using {@link Encoded#Encoded(String, String)} in APIs + * to distinguish encoded from unencoded data by type. + *
+ * + * @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 '%'. + *+ * For example: Euro currency symbol -> "%E2%82%AC". + *
+ *+ * Consider using {@link ASCIIEncoded#ASCIIEncoded(String)} in APIs + * to distinguish encoded from unencoded data by type. + *
+ * @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. + *+ *'%' and two following hex digit characters are converted to the + * equivalent byte value. All other characters are passed through + * unmodified. + *
+ *+ * e.g. "A%20B%20C %24%25" -> "A B C $%" + *
+ * + * @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. + *+ * This constructor first creates a temporary Uri string from the given components. This + * string will be parsed later on to create the Uri instance. + *
+ *+ * {@code [scheme:]scheme-specific-part[#fragment]} + *
+ * + * @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(IOUtil.SCHEME_SEPARATOR); + } + if ( !emptyString(ssp) ) { + // QUOTE ILLEGAL CHARACTERS + uri.append(encode(ssp, SSP_LEGAL)); + } + if ( !emptyString(fragment) ) { + uri.append(IOUtil.FRAGMENT_SEPARATOR); + // QUOTE ILLEGAL CHARACTERS + uri.append(encode(fragment, FRAG_LEGAL)); + } + return new Uri(new Encoded(uri.toString()), false); + } + + /** + * Creates a new Uri instance using the given arguments. + *+ * This constructor first creates a temporary Uri string from the given components. This + * string will be parsed later on to create the Uri instance. + *
+ *+ * {@code [scheme:][user-info@]host[:port][path][?query][#fragment]} + *
+ * + * @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 boolean extendedPath; + if( emptyString(query) || emptyString(fragment) ) { + extendedPath = true; + } else { + extendedPath = false; + } + + final StringBuilder uri = new StringBuilder(); + if ( !emptyString(scheme) ) { + uri.append(scheme); + uri.append(IOUtil.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(IOUtil.SCHEME_SEPARATOR) != -1 && host.indexOf(']') == -1 + && host.indexOf('[') == -1) { + host = "[" + host + "]"; + } + uri.append(host); + } + + if ( port != -1 ) { + uri.append(IOUtil.SCHEME_SEPARATOR); + uri.append(port); + } + + if ( !emptyString(path) ) { + // QUOTE ILLEGAL CHARS + uri.append(encode(path, extendedPath ? PATH_MIN_LEGAL : PATH_LEGAL)); + } + + if ( !emptyString(query) ) { + uri.append('?'); + // QUOTE ILLEGAL CHARS + uri.append(encode(query, QUERY_LEGAL)); + } + + if ( !emptyString(fragment) ) { + // QUOTE ILLEGAL CHARS + uri.append(IOUtil.FRAGMENT_SEPARATOR); + uri.append(encode(fragment, FRAG_LEGAL)); + } + return new Uri(new Encoded(uri.toString()), true); + } + + /** + * Creates a new Uri instance using the given arguments. + *+ * This constructor first creates a temporary Uri string from the given components. This + * string will be parsed later on to create the Uri instance. + *
+ *+ * {@code [scheme:]host[path][#fragment]} + *
+ * + * @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. + *+ * This constructor first creates a temporary Uri string from the given components. This + * string will be parsed later on to create the Uri instance. + *
+ *+ * {@code [scheme:][//authority][path][?query][#fragment]} + *
+ * + * @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 boolean extendedPath; + if( emptyString(query) || emptyString(fragment) ) { + extendedPath = true; + } else { + extendedPath = false; + } + + final StringBuilder uri = new StringBuilder(); + if ( !emptyString(scheme) ) { + uri.append(scheme); + uri.append(IOUtil.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, extendedPath ? PATH_MIN_LEGAL : PATH_LEGAL)); + } + if ( !emptyString(query) ) { + // QUOTE ILLEGAL CHARS + uri.append('?'); + uri.append(encode(query, QUERY_LEGAL)); + } + if ( !emptyString(fragment) ) { + // QUOTE ILLEGAL CHARS + uri.append(IOUtil.FRAGMENT_SEPARATOR); + uri.append(encode(fragment, FRAG_LEGAL)); + } + return new Uri(new Encoded(uri.toString()), false); + } + + /** + * 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)}. + *+ * No encoding will be performed on the given {@code encodedUri}, use with care. + *
+ * @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. + *+ * This constructor first creates a temporary Uri string from the given components. This + * string will be parsed later on to create the Uri instance. + *
+ *+ * {@code file:path} + *
+ * + * @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(IOUtil.FILE_SCHEME); + uri.append(IOUtil.SCHEME_SEPARATOR); + + // QUOTE ILLEGAL CHARS + uri.append(encode(path, PATH_MIN_LEGAL)); + + return new Uri(new Encoded(uri.toString()), false); + } + + /** + * Creates a new Uri instance using the given File instance. + *+ * This constructor first creates a temporary Uri string from the given components. This + * string will be parsed later on to create the Uri instance. + *
+ *+ * {@code file:path} + *
+ * + * @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. + *+ * If {@code reencode} is {@code true}, decomposes and decoded parts of the given URI + * and reconstruct a new encoded Uri instance, re-encoding will be performed. + *
+ *+ * If {@code reencode} is {@code false}, the encoded {@link URI#toString()} is being used for the new Uri instance, + * i.e. no re-encoding will be performed. + *
+ * + * @param uri A given URI instance + * @param reencode flag whether re-encoding shall be performed + * + * @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 URI uri, final boolean reencode) throws URISyntaxException { + if( !reencode) { + return new Uri(new Encoded(uri.toString())); + } + System.err.println("Uri.createByURI(reencode):"); + System.err.println(" source: "+uri.toString()); + final Uri recomposedUri; + if( uri.isOpaque()) { + // opaque, without host validation + System.err.println(" opaq source: ssp: "+uri.getSchemeSpecificPart()); + System.err.println(" opaq source: frg: "+uri.getFragment()); + recomposedUri = Uri.create(uri.getScheme(), uri.getSchemeSpecificPart(), uri.getFragment()); + } else if( null != uri.getHost() ) { + // with host validation + System.err.println(" host source: ssp: "+uri.getSchemeSpecificPart()); + System.err.println(" host source: frg: "+uri.getFragment()); + recomposedUri = Uri.create(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), + uri.getPath(), uri.getQuery(), uri.getFragment()); + } else { + // without host validation + System.err.println(" source: ssp: "+uri.getSchemeSpecificPart()); + System.err.println(" source: frg: "+uri.getFragment()); + recomposedUri = Uri.create(uri.getScheme(), uri.getAuthority(), + uri.getPath(), uri.getQuery(), uri.getFragment()); + } + System.err.println(" result: "+recomposedUri.toString()); + return recomposedUri; + } + + /** + * Creates a new Uri instance using the given URL instance. + *+ * No re-encoding will be performed. + *
+ * + * @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 URL url) throws URISyntaxException { + return new Uri(new Encoded(url.toString())); + } + + // + // 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; + + /** Plain {@code scheme}, {@code null} if undefined. */ + public final String 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}. + *+ * An opaque Uri has no {@code scheme-specific-part} being parsed, + * i.e. {@code path}, {@code query} and {@code authority} are {@code null}. + *
+ */ + 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); + } + + /** Returns true, if this instance is a {@code file} {@code scheme}, otherwise false. */ + public final boolean isFileScheme() { + return IOUtil.FILE_SCHEME.equals( scheme ); + } + + /** + * 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 #toURI(boolean) + */ + public final URI toURI() { + try { + return new URI(input.get()); + } catch (final URISyntaxException e) { + throw new Error(e); // Can't happen + } + } + + /** + * Returns a new {@link URI} instance based upon this instance. + *+ * If {@code reencode} is {@code true}, all Uri parts of this instance will be decoded + * and encoded by the URI constructor, i.e. re-encoding will be performed. + *
+ *+ * If {@code reencode} is {@code false}, this instance encoded {@link #input} string is being used, see {@link #toURI()}, + * i.e. no re-encoding will be performed. + *
+ * + * @throws URISyntaxException + * if the given string {@code uri} doesn't fit to the + * specification RFC2396 or could not be parsed correctly. + * @see #valueOf(URI, boolean) + */ + public final URI toURI(final boolean reencode) throws URISyntaxException { + if( !reencode ) { + return toURI(); + } + final URI recomposedURI; + if( opaque ) { + // opaque, without host validation + recomposedURI = new URI(decode(scheme), decode(schemeSpecificPart), decode(fragment)); + } else if( null != host ) { + // with host validation + recomposedURI = new URI(decode(scheme), decode(userInfo), decode(host), port, + decode(path), decode(query), decode(fragment)); + } else { + // without host validation + recomposedURI = new 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 URL toURL() throws MalformedURLException { + if (!absolute) { + throw new IllegalArgumentException("Cannot convert relative Uri: "+input); + } + return new URL(input.get()); + } + + /** + * If this instance {@link #isFileScheme() is a file scheme}, + * implementation decodes [ "//"+{@link #authority} ] + {@link #path}, == '\\'
+ * as follows:
+ * + * Otherwise implementation returns {@code null}. + *
+ */ + public final String getNativeFilePath() { + if( isFileScheme() ) { + final String authorityS; + if( null == authority ) { + authorityS = ""; + } else { + authorityS = "//"+authority.decode(); + } + // return IOUtil.decodeURIToFilePath(authorityS + path); + 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 r.substring(1); + } else { + return r; + } + } + return 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. + *+ * In case this Uri is a {@code jar-scheme}, the {@code query} is omitted, + * since it shall be invalid for {@code jar-schemes} anyway. + *
+ *+ * Otherwise method returns {@code null}. + *
+ *+ * Example 1: + * This instance:+ * @throws URISyntaxException + */ + public final Uri getContainedUri() throws URISyntaxException { + if( !emptyString(schemeSpecificPart) ) { + final StringBuilder sb = new StringBuilder(); + + if( scheme.equals(IOUtil.JAR_SCHEME) ) { + final int idx = schemeSpecificPart.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR); + if (0 > idx) { + throw new URISyntaxException(input.get(), "missing jar separator"); + } + sb.append( schemeSpecificPart.substring(0, idx) ); // exclude '!/' + } else { + sb.append( schemeSpecificPart.get() ); + } + if ( !emptyString(fragment) ) { + sb.append(IOUtil.FRAGMENT_SEPARATOR); + sb.append(fragment); + } + try { + final Uri res = new Uri(new Encoded(sb.toString()), false); + if( null != res.scheme ) { + return res; + } + } catch(final URISyntaxException e) { + // OK, does not contain uri + } + } + return null; + } + + + /** + * Return a new Uri instance representing the parent path of this Uri, + * while cutting of optional {@code query} and {@code fragment} parts. + *jar:scheme2:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
+ * Returned Uri:scheme2:/some/path/gluegen-rt.jar
+ * + * Example 2: + * This instance:jar:scheme2:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class?lala=01#fragment
+ * Returned Uri:scheme2:/some/path/gluegen-rt.jar#fragment
+ * + * Example 3: + * This instance:scheme1:scheme2:/some/path/gluegen-rt.jar?lala=01#fragment
+ * Returned Uri:scheme2:/some/path/gluegen-rt.jar?lala=01#fragment
+ *
+ * Method is {@code jar-file-entry} aware, i.e. will return the parent entry if exists. + *
+ *+ * If this Uri does not contain any path separator, method returns {@code null}. + *
+ *+ * Example-1: + * This instance :+ */ + 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+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.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+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.substring(0, p+1) )); + } catch (final URISyntaxException ue) { + // not complete, hence removed authority, or even root folder -> return null + } + } + } + } + return null; + } + + /// NEW START + + /** + * The URI'sjar:http://some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
+ * Returned Uri #1:jar:http://some/path/gluegen-rt.jar!/com/jogamp/common/
+ * Returned Uri #2:jar:http://some/path/gluegen-rt.jar!/com/jogamp/
+ * + * Example-2: + * This instance :http://some/path/gluegen-rt.jar
+ * Returned Uri #1:http://some/path/
+ * Returned Uri #2:http://some/
+ *
protocol:/some/path/gluegen-rt.jar
+ * parent dirname URI protocol:/some/path/
will be returned,
+ * or {@code null} if not applicable.
+ * + * protocol may be "file", "http", etc.. + *
+ * + * @return "protocol:/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) {} + return null; + } + + /** + * Generates a URI for the relativePath relative to the baseURI, + * hence the result is a absolute location. + *+ * Impl. operates on the scheme-specific-part, and hence is sub-protocol savvy. + *
+ *+ * In case baseURI is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used. + *
+ * + * @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../
+ */
+ public Uri getRelativeOf(final Encoded relativePath) throws URISyntaxException {
+ return compose(scheme, schemeSpecificPart, relativePath, fragment);
+ }
+
+ static Uri compose(final String 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);
+ 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}
+ * + * 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. + *
+ * + * @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} + *+ * Gets the hashcode value of this Uri instance. + *
+ */ + @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.substring(previndex, index).equals( second.substring(previndex, index) ) ) { + return false; + } + if( !first.substring(index + 1, index + 3).equalsIgnoreCase( second.substring(index + 1, index + 3) ) ) { + return false; + } + index += 3; + previndex = index; + } + return first.substring(previndex).equals( second.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.toLowerCase()); + result.append(IOUtil.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() + "@"); //$NON-NLS-1$ + } + result.append(host.get().toLowerCase()); + if (port != -1) { + result.append(IOUtil.SCHEME_SEPARATOR + port); + } + } + } + + if (path != null) { + result.append(path.get()); + } + + if (query != null) { + result.append('?'); + result.append(query.get()); + } + } + + if (fragment != null) { + result.append(IOUtil.FRAGMENT_SEPARATOR); + result.append(fragment.get()); + } + return convertHexToLowerCase(result.toString()); + } + + /** + * + * @param input + * @param expectServer + * @throws URISyntaxException + */ + private Uri(final Encoded input, final boolean expectServer) throws URISyntaxException { + if( emptyString(input) ) { + throw new URISyntaxException(input.get(), "empty input"); + } + this.input = input; + + String temp = input.get(); + int index; + // parse into Fragment, Scheme, and SchemeSpecificPart + // then parse SchemeSpecificPart if necessary + + // Fragment + index = temp.indexOf(IOUtil.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; + } + + // Scheme and SchemeSpecificPart + final int indexSchemeSep = temp.indexOf(IOUtil.SCHEME_SEPARATOR); + index = indexSchemeSep; + final int indexSSP = temp.indexOf('/'); + final int indexQuerySep = temp.indexOf('?'); + final String schemeSpecificPartS; + + // 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 = temp.substring(0, indexSchemeSep); + if (scheme.length() == 0) { + failExpecting(input, "scheme", indexSchemeSep); + } + validateScheme(input, scheme, 0); + schemeSpecificPartS = temp.substring(indexSchemeSep + 1); + schemeSpecificPart = new Encoded( schemeSpecificPartS ); + if (schemeSpecificPart.length() == 0) { + failExpecting(input, "scheme-specific-part", indexSchemeSep); + } + } else { + absolute = false; + scheme = null; + schemeSpecificPartS = temp; + schemeSpecificPart = new Encoded( schemeSpecificPartS ); + } + + if ( scheme == null || schemeSpecificPartS.length() > 0 && schemeSpecificPartS.charAt(0) == '/' ) { + // Uri is hierarchical, not opaque + opaque = false; + + // Query + temp = schemeSpecificPartS; + 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; + } + + // Authority and Path + if (temp.startsWith("//")) { + index = temp.indexOf('/', 2); + final String authorityS; + if (index != -1) { + authorityS = temp.substring(2, index); + path = new Encoded( temp.substring(index) ); + } else { + authorityS = temp.substring(2); + if (authorityS.length() == 0 && query == null && fragment == null) { + failExpecting(input, "authority, path [, query, fragment]", index); + } + path = Encoded.EMPTY; + // 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 + path = new Encoded( temp ); + authority = null; + } + + int pathIndex = 0; + if (indexSSP > -1) { + pathIndex += indexSSP; + } + if (index > -1) { + pathIndex += index; + } + validatePath(input, path, pathIndex); + } else { + // Uri is not hierarchical, Uri is opaque + opaque = true; + query = null; + path = null; + authority = null; + validateSsp(input, schemeSpecificPart, indexSchemeSep + 1); + } + + /** + * 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(IOUtil.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 String 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, "+-."); + if( 0 <= errIdx ) { + fail(uri, "invalid scheme", index+errIdx); + } + } + + private static void validateSsp(final Encoded uri, final Encoded 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, AUTHORITY_LEGAL); + if( 0 <= errIdx ) { + fail(uri, "invalid authority", index+errIdx); + } + } + + private static void validatePath(final Encoded uri, final Encoded 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, 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, 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, "."); //$NON-NLS-1$ + while (st.hasMoreTokens()) { + label = st.nextToken(); + if (label.startsWith("-") || label.endsWith("-")) { //$NON-NLS-1$ //$NON-NLS-2$ + 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 = ""; //$NON-NLS-1$ + 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) == IOUtil.SCHEME_SEPARATOR_CHAR) + && (ipv6Address.charAt(2) != IOUtil.SCHEME_SEPARATOR_CHAR)) { + 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) != IOUtil.SCHEME_SEPARATOR_CHAR + && ipv6Address.charAt(1 + offset) != IOUtil.SCHEME_SEPARATOR_CHAR) { + return false; + } + word = ""; //$NON-NLS-1$ + break; + + case IOUtil.SCHEME_SEPARATOR_CHAR: + numberOfColons++; + if (numberOfColons > 7) { + return false; + } + if (numberOfPeriods > 0) { + return false; + } + if (prevChar == IOUtil.SCHEME_SEPARATOR_CHAR) { + if (doubleColon) { + return false; + } + doubleColon = true; + } + word = ""; //$NON-NLS-1$ + 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) != IOUtil.SCHEME_SEPARATOR_CHAR //$NON-NLS-1$ + && ipv6Address.charAt(length - 2 - offset) != IOUtil.SCHEME_SEPARATOR_CHAR) { + 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: + *../
*/
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;
}
@@ -308,24 +316,6 @@ public class IOUtil {
return cleanPathString(p);
}
- /**
- * Using the simple conversion via File -> URI, assuming proper characters.
- * @throws URISyntaxException if path is empty or has no parent directory available while resolving ../
- * @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 ../
- * @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
@@ -445,6 +435,7 @@ public class IOUtil {
* @return "protocol:/some/path/"
* @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
* @throws URISyntaxException
+ * @deprecated Use {@link Uri#getDirectory()}
*/
public static URI getURIDirname(final URI uri) throws IllegalArgumentException, URISyntaxException {
if(null == uri) {
@@ -468,6 +459,7 @@ public class IOUtil {
* @return "protocol:/some/path/"
* @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
* @throws URISyntaxException
+ * @deprecated Use {@link Uri#getDirectory()}
*/
public static String getURIDirname(String uriS) throws IllegalArgumentException, URISyntaxException {
if(null == uriS) {
@@ -488,25 +480,11 @@ public class IOUtil {
uriS = uriS.substring(0, idx+1); // exclude jar name, include terminal '/' or ':'
if( DEBUG ) {
- System.err.println("getJarURIDirname res: "+uriS);
+ System.err.println("getURIDirname 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
@@ -705,177 +683,7 @@ public class IOUtil {
return path;
}
- /**
- * Generates a URI for the relativePath relative to the baseURI,
- * hence the result is a absolute location.
- * - * Impl. operates on the scheme-specific-part, and hence is sub-protocol savvy. - *
- *- * In case baseURI is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used. - *
- * - * @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../
- */
- 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 relativePath relative to the schemeSpecificPart,
- * hence the result is a absolute location.
- * - * schemeSpecificPart's query, if exist is split to path and query. - *
- *- * In case path is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used. - *
- * - * @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../
- * @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.
- *
- * Implementation processes the filePath
if {@link File#separatorChar} == '\\'
- * as follows:
- *
- * Note that this method does not perform space encoding, - * which can be utilized via {@link #encodeToURI(String)}. - *
- *
- * Even though Oracle's JarURLStreamHandler can handle backslashes and
- * erroneous URIs w/ e.g. Windows file 'syntax', other may not (Netbeans).
- * See Bug 857 - http://jogamp.org/bugzilla/show_bug.cgi?id=857
- *
- * Implementation decodes the space-encoding path={@link #decodeFromURI(String) decodeFromURI}(uriPath)
.
- *
- * Then it processes the path
if {@link File#separatorChar} == '\\'
- * as follows:
- *
uri
is a file scheme,
@@ -890,9 +698,7 @@ public class IOUtil {
* * Otherwise it returns the {@link URI#toASCIIString()} encoded URI. *
- * - * @see #decodeFromURI(String) - * @see #decodeURIToFilePath(String) + * @deprecated Use {@link Uri#getNativeFilePath()}. */ public static String decodeURIIfFilePath(final URI uri) { if( IOUtil.FILE_SCHEME.equals( uri.getScheme() ) ) { diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java index 3fe03bf..329ea51 100644 --- a/src/java/com/jogamp/common/util/JarUtil.java +++ b/src/java/com/jogamp/common/util/JarUtil.java @@ -46,6 +46,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; @@ -263,6 +264,7 @@ public class JarUtil { * @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)} + * @deprecated Use {@link Uri#getContainedUri()} and validate it's scheme, etc. */ public static URI getJarSubURI(final URI classJarURI) throws IllegalArgumentException, URISyntaxException { if(null == classJarURI) { diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java index 1b322d7..8979a43 100644 --- a/src/java/com/jogamp/common/util/cache/TempJarCache.java +++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java @@ -38,6 +38,7 @@ 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; @@ -412,7 +413,7 @@ public class TempJarCache { checkInitialized(); final File f = new File(tmpFileCache.getTempDir(), name); if(f.exists()) { - return IOUtil.toURISimple(f); + return Uri.valueOf(f).toURI(); } return null; } -- cgit v1.2.3 From 2d615932505d4870f3fd0dd37f21fb3d308ab536 Mon Sep 17 00:00:00 2001 From: Sven Gothel- * Excluding special native filesystem characters to be encoded. - *
- *- * {@value} + {@code alphanum} - *
- */ - public static final String PATH_MIN_LEGAL = "/!_-."; // "/!" + ( unreserved - '~' ) + 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}, @@ -232,6 +226,7 @@ public class Uri { * */ public static final String QUERY_LEGAL = UNRESERVED + RESERVED_2 + "\\\""; + // Harmony: unreserved + reserved + "\\\"" /** * Valid charset for RFC 2396 {@code scheme-specific-part}, @@ -241,6 +236,7 @@ public class Uri { * */ public static final String SSP_LEGAL = QUERY_LEGAL; + // Harmony: unreserved + reserved /** * Valid charset for RFC 2396 {@code fragment}, @@ -250,6 +246,7 @@ public class Uri { * */ public static final String FRAG_LEGAL = UNRESERVED + RESERVED; + // Harmony: unreserved + reserved /** * Immutable RFC3986 encoded string. @@ -651,13 +648,6 @@ public class Uri { throw new URISyntaxException(path, "path doesn't start with '/'"); } - final boolean extendedPath; - if( emptyString(query) || emptyString(fragment) ) { - extendedPath = true; - } else { - extendedPath = false; - } - final StringBuilder uri = new StringBuilder(); if ( !emptyString(scheme) ) { uri.append(scheme); @@ -691,7 +681,7 @@ public class Uri { if ( !emptyString(path) ) { // QUOTE ILLEGAL CHARS - uri.append(encode(path, extendedPath ? PATH_MIN_LEGAL : PATH_LEGAL)); + uri.append(encode(path, PATH_LEGAL)); } if ( !emptyString(query) ) { @@ -759,13 +749,6 @@ public class Uri { throw new URISyntaxException(path, "path doesn't start with '/'"); } - final boolean extendedPath; - if( emptyString(query) || emptyString(fragment) ) { - extendedPath = true; - } else { - extendedPath = false; - } - final StringBuilder uri = new StringBuilder(); if ( !emptyString(scheme) ) { uri.append(scheme); @@ -779,7 +762,7 @@ public class Uri { if ( !emptyString(path) ) { // QUOTE ILLEGAL CHARS - uri.append(encode(path, extendedPath ? PATH_MIN_LEGAL : PATH_LEGAL)); + uri.append(encode(path, PATH_LEGAL)); } if ( !emptyString(query) ) { // QUOTE ILLEGAL CHARS @@ -834,7 +817,7 @@ public class Uri { uri.append(IOUtil.SCHEME_SEPARATOR); // QUOTE ILLEGAL CHARS - uri.append(encode(path, PATH_MIN_LEGAL)); + uri.append(encode(path, PATH_LEGAL)); return new Uri(new Encoded(uri.toString()), false); } diff --git a/src/junit/com/jogamp/common/net/TestUri03Resolving.java b/src/junit/com/jogamp/common/net/TestUri03Resolving.java index 0d65363..7c1dadf 100644 --- a/src/junit/com/jogamp/common/net/TestUri03Resolving.java +++ b/src/junit/com/jogamp/common/net/TestUri03Resolving.java @@ -72,31 +72,30 @@ public class TestUri03Resolving extends JunitTracer { }; public static final String[][] uriFileSArrayWindows = new String[][] { - new String[] {"file:/C:/gluegen/build-x86_64/gluegen-rt.jar"}, new String[] {"file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar"}, - new String[] {"file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar"}, + new String[] {"file:/C%3A/gluegen/"+'\u0394'+"/gluegen-rt.jar"}, - new String[] {"file:/C:/gluegen/build-x86_64%20lala/gluegen-rt.jar"}, + new String[] {"file:/C%3A/gluegen/build-x86_64%20lala/gluegen-rt.jar"}, - new String[] {"file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"}, + new String[] {"file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"}, - new String[] {"jar:file:/C:/gluegen/build-x86_64/gluegen-rt.jar!/"}, + new String[] {"jar:file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar!/"}, - new String[] {"jar:file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"}, + new String[] {"jar:file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"}, - new String[] {"jar:file:/C:/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, + new String[] {"jar:file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, - new String[] {"jar:file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, + new String[] {"jar:file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, new String[] {"jar:file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, - new String[] {"jar:file:///C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, + new String[] {"jar:file:///C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, new String[] {"jar:file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"}, - new String[] {"jar:file:/C:/gluegen/R%23/gluegen-rt.jar!/"}, + new String[] {"jar:file:/C%3A/gluegen/R%23/gluegen-rt.jar!/"}, - new String[] {"jar:file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"}, + new String[] {"jar:file:/C%3A/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"}, }; public static final String[][] fileSArrayUnix = new String[][] { @@ -117,11 +116,11 @@ public class TestUri03Resolving extends JunitTracer { "/gluegen/build-x86_64 öä lala/gluegen-rt.jar"}, new String[] {"/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar", - "file:/gluegen/A%24/B%5E/C%7E/D%23/E%5B/F%5D/gluegen-rt.jar", + "file:/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar", "/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar" }, new String[] {"/gluegen/$/^/~/#/[/]/gluegen-rt.jar", - "file:/gluegen/%24/%5E/%7E/%23/%5B/%5D/gluegen-rt.jar", + "file:/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar", "/gluegen/$/^/~/#/[/]/gluegen-rt.jar" }, }; @@ -151,11 +150,11 @@ public class TestUri03Resolving extends JunitTracer { "\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"}, new String[] {"C:/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar", - "file:/C%3A/gluegen/A%24/B%5E/C%7E/D%23/E%5B/F%5D/gluegen-rt.jar", + "file:/C%3A/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar", "C:\\gluegen\\A$\\B^\\C~\\D#\\E[\\F]\\gluegen-rt.jar" }, new String[] {"C:/gluegen/$/^/~/#/[/]/gluegen-rt.jar", - "file:/C%3A/gluegen/%24/%5E/%7E/%23/%5B/%5D/gluegen-rt.jar", + "file:/C%3A/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar", "C:\\gluegen\\$\\^\\~\\#\\[\\]\\gluegen-rt.jar" }, }; -- cgit v1.2.3 From 6322991799268166e46aeeacb142c11d45950f48 Mon Sep 17 00:00:00 2001 From: Sven Gothel+ * Returns the encoded String, same as {@link #get()}. + *
+ */ @Override public final String toString() { return s; } @@ -366,9 +373,9 @@ public class Uri { public Encoded concat(final Encoded encoded) { return new Encoded(s.concat(encoded.s)); } /** See {@link String#substring(int)}. */ - public final String substring(final int start) { return s.substring(start); } + public final Encoded substring(final int start) { return new Encoded(s.substring(start)); } /** See {@link String#substring(int, int)}. */ - public final String substring(final int start, final int end) { return s.substring(start, end); } + 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); } @@ -864,28 +871,19 @@ public class Uri { if( !reencode) { return new Uri(new Encoded(uri.toString())); } - System.err.println("Uri.createByURI(reencode):"); - System.err.println(" source: "+uri.toString()); final Uri recomposedUri; if( uri.isOpaque()) { // opaque, without host validation - System.err.println(" opaq source: ssp: "+uri.getSchemeSpecificPart()); - System.err.println(" opaq source: frg: "+uri.getFragment()); recomposedUri = Uri.create(uri.getScheme(), uri.getSchemeSpecificPart(), uri.getFragment()); } else if( null != uri.getHost() ) { // with host validation - System.err.println(" host source: ssp: "+uri.getSchemeSpecificPart()); - System.err.println(" host source: frg: "+uri.getFragment()); recomposedUri = Uri.create(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment()); } else { // without host validation - System.err.println(" source: ssp: "+uri.getSchemeSpecificPart()); - System.err.println(" source: frg: "+uri.getFragment()); recomposedUri = Uri.create(uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment()); } - System.err.println(" result: "+recomposedUri.toString()); return recomposedUri; } @@ -919,8 +917,8 @@ public class Uri { private int hash; - /** Plain {@code scheme}, {@code null} if undefined. */ - public final String scheme; + /** Encoded {@code scheme}, {@code null} if undefined. */ + public final Encoded scheme; /** Encoded {@code scheme-specific-part}, never {@code null}. */ public final Encoded schemeSpecificPart; @@ -970,7 +968,7 @@ public class Uri { /** Returns true, if this instance is a {@code file} {@code scheme}, otherwise false. */ public final boolean isFileScheme() { - return IOUtil.FILE_SCHEME.equals( scheme ); + return IOUtil.FILE_SCHEME.equals( scheme.get() ); } /** @@ -1134,7 +1132,7 @@ public class Uri { if (0 > idx) { throw new URISyntaxException(input.get(), "missing jar separator"); } - sb.append( schemeSpecificPart.substring(0, idx) ); // exclude '!/' + sb.append( schemeSpecificPart.get().substring(0, idx) ); // exclude '!/' } else { sb.append( schemeSpecificPart.get() ); } @@ -1184,7 +1182,7 @@ public class Uri { if( e < pl - 1 ) { // path is file or has a query try { - return new Uri(new Encoded( scheme+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.substring(0, e+1) )); + return new Uri( new Encoded( scheme.get()+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.get().substring(0, e+1) ) ); } catch (final URISyntaxException ue) { // not complete, hence removed authority, or even root folder -> return null } @@ -1193,7 +1191,7 @@ public class Uri { final int p = schemeSpecificPart.lastIndexOf("/", e-1); if( p > 0 ) { try { - return new Uri(new Encoded( scheme+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.substring(0, p+1) )); + return new Uri( new Encoded( scheme.get()+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.get().substring(0, p+1) ) ); } catch (final URISyntaxException ue) { // not complete, hence removed authority, or even root folder -> return null } @@ -1256,7 +1254,7 @@ public class Uri { return compose(scheme, schemeSpecificPart, relativePath, fragment); } - static Uri compose(final String scheme, final Encoded schemeSpecificPart, final Encoded relativePath, final Encoded fragment) throws URISyntaxException { + 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 @@ -1276,7 +1274,7 @@ public class Uri { } schemeSpecificPartS = IOUtil.cleanPathString( schemeSpecificPartS ); final StringBuilder uri = new StringBuilder(); - uri.append(scheme); + uri.append(scheme.get()); uri.append(':'); uri.append(schemeSpecificPartS); if ( null != query ) { @@ -1430,16 +1428,16 @@ public class Uri { while ( ( index = first.indexOf('%', previndex) ) != -1 && second.indexOf('%', previndex) == index ) { - if( !first.substring(previndex, index).equals( second.substring(previndex, index) ) ) { + if( !first.get().substring(previndex, index).equals( second.get().substring(previndex, index) ) ) { return false; } - if( !first.substring(index + 1, index + 3).equalsIgnoreCase( second.substring(index + 1, index + 3) ) ) { + if( !first.get().substring(index + 1, index + 3).equalsIgnoreCase( second.get().substring(index + 1, index + 3) ) ) { return false; } index += 3; previndex = index; } - return first.substring(previndex).equals( second.substring(previndex) ); + return first.get().substring(previndex).equals( second.get().substring(previndex) ); } /* @@ -1450,7 +1448,7 @@ public class Uri { private String getHashString() { final StringBuilder result = new StringBuilder(); if (scheme != null) { - result.append(scheme.toLowerCase()); + result.append(scheme.get().toLowerCase()); result.append(IOUtil.SCHEME_SEPARATOR); } if (opaque) { @@ -1531,7 +1529,7 @@ public class Uri { ) { // the characters up to the first ':' comprise the scheme absolute = true; - scheme = temp.substring(0, indexSchemeSep); + scheme = new Encoded( temp.substring(0, indexSchemeSep) ); if (scheme.length() == 0) { failExpecting(input, "scheme", indexSchemeSep); } @@ -1696,13 +1694,13 @@ public class Uri { } } - private static void validateScheme(final Encoded uri, final String scheme, final int index) throws URISyntaxException { + 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, "+-."); + final int errIdx = validateAlphaNum(scheme.get(), "+-."); if( 0 <= errIdx ) { fail(uri, "invalid scheme", index+errIdx); } diff --git a/src/junit/com/jogamp/common/net/TestUri01.java b/src/junit/com/jogamp/common/net/TestUri01.java index 361304c..652caa6 100644 --- a/src/junit/com/jogamp/common/net/TestUri01.java +++ b/src/junit/com/jogamp/common/net/TestUri01.java @@ -28,7 +28,7 @@ public class TestUri01 extends JunitTracer { final String vanilla = "XXX ! # $ & ' ( ) * + , / : ; = ? @ [ ]"; final Uri.Encoded escaped = Uri.Encoded.cast("XXX%20!%20%23%20%24%20%26%20%27%20%28%20%29%20%2A%20%2B%20%2C%20/%20%3A%20%3B%20%3D%20%3F%20%40%20%5B%20%5D"); System.err.println("vanilla "+vanilla); - final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_MIN_LEGAL); + final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_LEGAL); System.err.println("esc1 "+esc1); Assert.assertEquals(escaped, esc1); @@ -40,7 +40,7 @@ public class TestUri01 extends JunitTracer { final String vanilla = "/XXX R!# R$&'()*+,/:;=?z@y[x]"; final Uri.Encoded escaped = Uri.Encoded.cast("/XXX%20R!%23%20R%24%26%27%28%29%2A%2B%2C/%3A%3B%3D%3Fz%40y%5Bx%5D"); System.err.println("vanilla "+vanilla); - final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_MIN_LEGAL); + final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_LEGAL); System.err.println("esc1 "+esc1); Assert.assertEquals(escaped, esc1); @@ -63,9 +63,9 @@ public class TestUri01 extends JunitTracer { public void test01URIEscapeCommonChars() throws IOException, URISyntaxException { { final String vanilla = "/XXX \"%-.<>\\^_`{|}~"; - final Uri.Encoded escaped = Uri.Encoded.cast("/XXX%20%22%25-.%3C%3E%5C%5E_%60%7B%7C%7D%7E"); + final Uri.Encoded escaped = Uri.Encoded.cast("/XXX%20%22%25-.%3C%3E%5C%5E_%60%7B%7C%7D~"); System.err.println("vanilla "+vanilla); - final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_MIN_LEGAL); + final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_LEGAL); System.err.println("esc1 "+esc1); Assert.assertEquals(escaped, esc1); diff --git a/src/junit/com/jogamp/common/net/TestUri03Resolving.java b/src/junit/com/jogamp/common/net/TestUri03Resolving.java index 7c1dadf..9445100 100644 --- a/src/junit/com/jogamp/common/net/TestUri03Resolving.java +++ b/src/junit/com/jogamp/common/net/TestUri03Resolving.java @@ -2,7 +2,6 @@ package com.jogamp.common.net; import java.io.File; import java.io.IOException; -import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; @@ -146,7 +145,7 @@ public class TestUri03Resolving extends JunitTracer { "C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"}, new String[] {"\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar", - "file:////filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar", + "file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar", "\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"}, new String[] {"C:/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar", @@ -167,71 +166,51 @@ public class TestUri03Resolving extends JunitTracer { System.err.println("file.path.dec "+file.getPath()); System.err.println("file.path.abs "+file.getAbsolutePath()); System.err.println("file.path.can "+file.getCanonicalPath()); - final URI uri0 = file.toURI(); - System.err.println("uri0.string: "+uri0.toString()); - System.err.println("uri0.path : "+uri0.getPath()); - System.err.println("uri0.ascii : "+uri0.toASCIIString()); + final Uri uri0 = Uri.valueOf(file); + URIDumpUtil.showUri(uri0); + URIDumpUtil.showReencodedURIOfUri(uri0); + boolean ok = true; - { - final URI uri1 = Uri.valueOf(file).toURI(); - final boolean equalString= uri0.toString().equals(uri1.toString()); - final boolean equalPath = uri0.getPath().equals(uri1.getPath()); - final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString()); - System.err.println("uri1.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); - System.err.println("uri1.path : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR")); - System.err.println("uri1.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); - ok = equalString && equalPath && equalASCII && ok; - } { final String s2 = IOUtil.slashify(file.getAbsolutePath(), true /* startWithSlash */, file.isDirectory() /* endWithSlash */); System.err.println("uri2.slashify: "+s2); - { - final URI uri1 = new URI(IOUtil.FILE_SCHEME, null, s2, null); - final boolean equalString= uri0.toString().equals(uri1.toString()); - final boolean equalPath = uri0.getPath().equals(uri1.getPath()); - final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString()); - System.err.println("uri2.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); - System.err.println("uri2.path : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR")); - System.err.println("uri2.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); - ok = equalString && equalPath && equalASCII && ok; - } - final URI uri1 = new URI(IOUtil.FILE_SCHEME, null, s2, null); - final boolean equalString= uri0.toString().equals(uri1.toString()); - final boolean equalPath = uri0.getPath().equals(uri1.getPath()); - final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString()); - System.err.println("uri2.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); - System.err.println("uri2.path : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR")); - System.err.println("uri2.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); - ok = equalString && equalPath && equalASCII && ok; + final Uri uri1 = Uri.create(IOUtil.FILE_SCHEME, null, s2, null); + final boolean equalEncoded= uri0.getEncoded().equals(uri1.getEncoded()); + final boolean equalPath = uri0.path.decode().equals(uri1.path.decode()); + final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString().get()); + System.err.println("uri2.enc : "+uri1.getEncoded()+" - "+(equalEncoded?"OK":"ERROR")); + System.err.println("uri2.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR")); + System.err.println("uri2.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); + ok = equalEncoded && equalPath && equalASCII && ok; } { final String s2 = "/"+string; System.err.println("uri3.orig: "+s2); - final URI uri1 = new URI(IOUtil.FILE_SCHEME, s2, null); + final Uri uri1 = Uri.create(IOUtil.FILE_SCHEME, s2, null); final String rString = "file:/Hallo%20Welt%20öä"; final String rPath = s2; final String rASCII = "file:/Hallo%20Welt%20%C3%B6%C3%A4"; - final boolean equalString= rString.equals(uri1.toString()); - final boolean equalPath = rPath.equals(uri1.getPath()); - final boolean equalASCII= rASCII.equals(uri1.toASCIIString()); - System.err.println("uri3.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); - System.err.println("uri3.path : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR")); - System.err.println("uri3.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); - ok = equalString && equalPath && equalASCII && ok; + final boolean equalEncoded = rString.equals(uri1.toString()); + final boolean equalPath = rPath.equals(uri1.path.decode()); + final boolean equalASCII= rASCII.equals(uri1.toASCIIString().get()); + System.err.println("uri3.enc : "+uri1.toString()+" - "+(equalEncoded?"OK":"ERROR")); + System.err.println("uri3.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR")); + System.err.println("uri3.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); + ok = equalEncoded && equalPath && equalASCII && ok; } { final String s2 = "//lala.org/"+string; System.err.println("uri4.orig: "+s2); - final URI uri1 = new URI(IOUtil.HTTP_SCHEME, s2, null); + final Uri uri1 = Uri.create(IOUtil.HTTP_SCHEME, s2, null); final String rString = "http://lala.org/Hallo%20Welt%20öä"; final String rPath = "/"+string; final String rASCII = "http://lala.org/Hallo%20Welt%20%C3%B6%C3%A4"; final boolean equalString= rString.equals(uri1.toString()); - final boolean equalPath = rPath.equals(uri1.getPath()); - final boolean equalASCII= rASCII.equals(uri1.toASCIIString()); - System.err.println("uri4.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); - System.err.println("uri4.path : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR")); - System.err.println("uri4.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); + final boolean equalPath = rPath.equals(uri1.path.decode()); + final boolean equalASCII= rASCII.equals(uri1.toASCIIString().get()); + System.err.println("uri4.enc : "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); + System.err.println("uri4.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR")); + System.err.println("uri4.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); ok = equalString && equalPath && equalASCII && ok; } Assert.assertTrue("One or more errors occured see stderr above", ok); -- cgit v1.2.3 From dde91a061cb0bc209442fe0e74a532b91d1bb4b8 Mon Sep 17 00:00:00 2001 From: Sven Gothel+ * 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! + *
+ *+ * 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. ':', '$', .. + *
+ */ + private static final int PARSE_HINT_FIX_PATH = 1 << 0; + private static final String DIGITS = "0123456789ABCDEF"; private static final String ENCODING = "UTF8"; @@ -248,12 +273,25 @@ public class Uri { 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- * If {@code reencode} is {@code true}, decomposes and decoded parts of the given URI - * and reconstruct a new encoded Uri instance, re-encoding will be performed. + * Re-encoding will be performed if the given URI is {@link URI#isOpaque() not opaque}. *
*- * If {@code reencode} is {@code false}, the encoded {@link URI#toString()} is being used for the new Uri instance, - * i.e. no re-encoding will be performed. + * See {@link #PARSE_HINT_FIX_PATH} for issues of injecting opaque URLs. *
* * @param uri A given URI instance - * @param reencode flag whether re-encoding shall be performed - * * @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 URI uri, final boolean reencode) throws URISyntaxException { - if( !reencode) { - return new Uri(new Encoded(uri.toString())); - } - final Uri recomposedUri; + public static Uri valueOf(final java.net.URI uri) throws URISyntaxException { if( uri.isOpaque()) { - // opaque, without host validation - recomposedUri = Uri.create(uri.getScheme(), uri.getSchemeSpecificPart(), uri.getFragment()); + // 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 - recomposedUri = Uri.create(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), - uri.getPath(), uri.getQuery(), uri.getFragment()); + return Uri.create(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), + uri.getPath(), uri.getQuery(), uri.getFragment()); } else { // without host validation - recomposedUri = Uri.create(uri.getScheme(), uri.getAuthority(), - uri.getPath(), uri.getQuery(), uri.getFragment()); + return Uri.create(uri.getScheme(), uri.getAuthority(), + uri.getPath(), uri.getQuery(), uri.getFragment()); } - return recomposedUri; } /** - * Creates a new Uri instance using the given URL instance. + * Creates a new Uri instance using the given URL instance, + * convenient wrapper for {@link #valueOf(URI)} and {@link URL#toURI()}. + *+ * Re-encoding will be performed if the given URL is {@link URI#isOpaque() not opaque}, see {@link #valueOf(URI)}. + *
*- * No re-encoding will be performed. + * See {@link #PARSE_HINT_FIX_PATH} for issues of injecting opaque URLs. *
* * @param url A given URL instance @@ -899,8 +938,8 @@ public class Uri { * if the temporary created string doesn't fit to the * specification RFC2396 or could not be parsed correctly. */ - public static Uri valueOf(final URL url) throws URISyntaxException { - return new Uri(new Encoded(url.toString())); + public static Uri valueOf(final java.net.URL url) throws URISyntaxException { + return valueOf(url.toURI()); } // @@ -963,12 +1002,12 @@ public class Uri { * specification RFC2396 and RFC3986 or could not be parsed correctly. */ public Uri(final Encoded uri) throws URISyntaxException { - this(uri, false); + this(uri, false, 0); } /** Returns true, if this instance is a {@code file} {@code scheme}, otherwise false. */ public final boolean isFileScheme() { - return IOUtil.FILE_SCHEME.equals( scheme.get() ); + return FILE_SCHEME.equals( scheme.get() ); } /** @@ -1001,11 +1040,12 @@ public class Uri { /** * 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 #toURI(boolean) + * @see #toURIReencoded(boolean) + * @see #valueOf(URI) */ - public final URI toURI() { + public final java.net.URI toURI() { try { - return new URI(input.get()); + return new java.net.URI(input.get()); } catch (final URISyntaxException e) { throw new Error(e); // Can't happen } @@ -1014,35 +1054,29 @@ public class Uri { /** * Returns a new {@link URI} instance based upon this instance. *- * If {@code reencode} is {@code true}, all Uri parts of this instance will be decoded + * All Uri parts of this instance will be decoded * and encoded by the URI constructor, i.e. re-encoding will be performed. *
- *- * If {@code reencode} is {@code false}, this instance encoded {@link #input} string is being used, see {@link #toURI()}, - * i.e. no re-encoding will be performed. - *
* * @throws URISyntaxException * if the given string {@code uri} doesn't fit to the * specification RFC2396 or could not be parsed correctly. - * @see #valueOf(URI, boolean) + * @see #toURI() + * @see #valueOf(URI) */ - public final URI toURI(final boolean reencode) throws URISyntaxException { - if( !reencode ) { - return toURI(); - } - final URI recomposedURI; + public final java.net.URI toURIReencoded() throws URISyntaxException { + final java.net.URI recomposedURI; if( opaque ) { // opaque, without host validation - recomposedURI = new URI(decode(scheme), decode(schemeSpecificPart), decode(fragment)); + recomposedURI = new java.net.URI(decode(scheme), decode(schemeSpecificPart), decode(fragment)); } else if( null != host ) { // with host validation - recomposedURI = new URI(decode(scheme), decode(userInfo), decode(host), port, - decode(path), decode(query), decode(fragment)); + recomposedURI = new java.net.URI(decode(scheme), decode(userInfo), decode(host), port, + decode(path), decode(query), decode(fragment)); } else { // without host validation - recomposedURI = new URI(decode(scheme), decode(authority), - decode(path), decode(query), decode(fragment)); + recomposedURI = new java.net.URI(decode(scheme), decode(authority), + decode(path), decode(query), decode(fragment)); } return recomposedURI; } @@ -1055,11 +1089,11 @@ public class Uri { * if an error occurs while creating the URL or no protocol * handler could be found. */ - public final URL toURL() throws MalformedURLException { + public final java.net.URL toURL() throws MalformedURLException { if (!absolute) { throw new IllegalArgumentException("Cannot convert relative Uri: "+input); } - return new URL(input.get()); + return new java.net.URL(input.get()); } /** @@ -1071,11 +1105,12 @@ public class Uri { ** Otherwise implementation returns {@code null}. *
*/ - public final String getNativeFilePath() { + public final File toFile() { if( isFileScheme() ) { final String authorityS; if( null == authority ) { @@ -1083,17 +1118,16 @@ public class Uri { } else { authorityS = "//"+authority.decode(); } - // return IOUtil.decodeURIToFilePath(authorityS + path); 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 r.substring(1); + return new File(r.substring(1)); } else { - return r; + return new File(r); } } - return path; + return new File(path); } return null; } @@ -1127,8 +1161,8 @@ public class Uri { if( !emptyString(schemeSpecificPart) ) { final StringBuilder sb = new StringBuilder(); - if( scheme.equals(IOUtil.JAR_SCHEME) ) { - final int idx = schemeSpecificPart.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR); + if( scheme.equals(JAR_SCHEME) ) { + final int idx = schemeSpecificPart.lastIndexOf(JAR_SCHEME_SEPARATOR); if (0 > idx) { throw new URISyntaxException(input.get(), "missing jar separator"); } @@ -1137,16 +1171,20 @@ public class Uri { sb.append( schemeSpecificPart.get() ); } if ( !emptyString(fragment) ) { - sb.append(IOUtil.FRAGMENT_SEPARATOR); + sb.append(FRAGMENT_SEPARATOR); sb.append(fragment); } try { - final Uri res = new Uri(new Encoded(sb.toString()), false); + 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; @@ -1160,7 +1198,7 @@ public class Uri { * Method is {@code jar-file-entry} aware, i.e. will return the parent entry if exists. * *- * If this Uri does not contain any path separator, method returns {@code null}. + * If this Uri does not contain any path separator, or a parent folder Uri cannot be found, method returns {@code null}. *
** Example-1: @@ -1182,7 +1220,7 @@ public class Uri { if( e < pl - 1 ) { // path is file or has a query try { - return new Uri( new Encoded( scheme.get()+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.get().substring(0, e+1) ) ); + 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 } @@ -1191,7 +1229,7 @@ public class Uri { final int p = schemeSpecificPart.lastIndexOf("/", e-1); if( p > 0 ) { try { - return new Uri( new Encoded( scheme.get()+IOUtil.SCHEME_SEPARATOR+schemeSpecificPart.get().substring(0, p+1) ) ); + 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 } @@ -1201,6 +1239,22 @@ public class Uri { 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 /** @@ -1232,7 +1286,11 @@ public class Uri { } try { return Uri.cast(uriS.substring(0, idx+1)); // exclude jar name, include terminal '/' or ':' - } catch (final URISyntaxException ue) {} + } catch (final URISyntaxException ue) { + if( DEBUG ) { + ue.printStackTrace(); + } + } return null; } @@ -1449,7 +1507,7 @@ public class Uri { final StringBuilder result = new StringBuilder(); if (scheme != null) { result.append(scheme.get().toLowerCase()); - result.append(IOUtil.SCHEME_SEPARATOR); + result.append(SCHEME_SEPARATOR); } if (opaque) { result.append(schemeSpecificPart.get()); @@ -1460,11 +1518,11 @@ public class Uri { result.append(authority.get()); } else { if (userInfo != null) { - result.append(userInfo.get() + "@"); //$NON-NLS-1$ + result.append(userInfo.get() + "@"); } result.append(host.get().toLowerCase()); if (port != -1) { - result.append(IOUtil.SCHEME_SEPARATOR + port); + result.append(SCHEME_SEPARATOR + port); } } } @@ -1480,7 +1538,7 @@ public class Uri { } if (fragment != null) { - result.append(IOUtil.FRAGMENT_SEPARATOR); + result.append(FRAGMENT_SEPARATOR); result.append(fragment.get()); } return convertHexToLowerCase(result.toString()); @@ -1490,21 +1548,20 @@ public class Uri { * * @param input * @param expectServer + * @param parseHints TODO * @throws URISyntaxException */ - private Uri(final Encoded input, final boolean expectServer) 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"); } - this.input = input; - String temp = input.get(); int index; // parse into Fragment, Scheme, and SchemeSpecificPart // then parse SchemeSpecificPart if necessary // Fragment - index = temp.indexOf(IOUtil.FRAGMENT_SEPARATOR); + index = temp.indexOf(FRAGMENT_SEPARATOR); if (index != -1) { // remove the fragment from the end fragment = new Encoded( temp.substring(index + 1) ); @@ -1514,12 +1571,15 @@ public class Uri { fragment = null; } + String inputTemp = input.get(); // may get modified due to error correction + // Scheme and SchemeSpecificPart - final int indexSchemeSep = temp.indexOf(IOUtil.SCHEME_SEPARATOR); + final int indexSchemeSep = temp.indexOf(SCHEME_SEPARATOR); index = indexSchemeSep; final int indexSSP = temp.indexOf('/'); final int indexQuerySep = temp.indexOf('?'); - final String schemeSpecificPartS; + + 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 @@ -1534,24 +1594,22 @@ public class Uri { failExpecting(input, "scheme", indexSchemeSep); } validateScheme(input, scheme, 0); - schemeSpecificPartS = temp.substring(indexSchemeSep + 1); - schemeSpecificPart = new Encoded( schemeSpecificPartS ); - if (schemeSpecificPart.length() == 0) { + sspTemp = temp.substring(indexSchemeSep + 1); + if (sspTemp.length() == 0) { failExpecting(input, "scheme-specific-part", indexSchemeSep); } } else { absolute = false; scheme = null; - schemeSpecificPartS = temp; - schemeSpecificPart = new Encoded( schemeSpecificPartS ); + sspTemp = temp; } - if ( scheme == null || schemeSpecificPartS.length() > 0 && schemeSpecificPartS.charAt(0) == '/' ) { + if ( scheme == null || sspTemp.length() > 0 && sspTemp.charAt(0) == '/' ) { // Uri is hierarchical, not opaque opaque = false; // Query - temp = schemeSpecificPartS; + temp = sspTemp; index = temp.indexOf('?'); if (index != -1) { query = new Encoded( temp.substring(index + 1) ); @@ -1561,19 +1619,24 @@ public class Uri { 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); - path = new Encoded( temp.substring(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); } - path = Encoded.EMPTY; + pathTemp = ""; + indexPathInSSP = -1; // nothing left, so path is empty // (not null, path should never be null if hierarchical/non-opaque) } @@ -1584,26 +1647,67 @@ public class Uri { validateAuthority(input, authority, indexSchemeSep + 3); } } else { // no authority specified - path = new Encoded( temp ); + pathTemp = temp; + indexPathInSSP = 0; authority = null; } - int pathIndex = 0; + int indexPath = 0; // in input if (indexSSP > -1) { - pathIndex += indexSSP; + indexPath += indexSSP; + } + if (indexPathInSSP > -1) { + indexPath += indexPathInSSP; } - if (index > -1) { - pathIndex += index; + + 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); + } } - validatePath(input, path, pathIndex); + path = new Encoded( pathTemp ); } else { // Uri is not hierarchical, Uri is opaque opaque = true; query = null; path = null; authority = null; - validateSsp(input, schemeSpecificPart, indexSchemeSep + 1); + 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 @@ -1635,7 +1739,7 @@ public class Uri { hostindex = index + 1; } - index = temp.lastIndexOf(IOUtil.SCHEME_SEPARATOR); + index = temp.lastIndexOf(SCHEME_SEPARATOR); final int endindex = temp.indexOf(']'); if (index != -1 && endindex < index) { @@ -1706,7 +1810,7 @@ public class Uri { } } - private static void validateSsp(final Encoded uri, final Encoded ssp, final int index) throws URISyntaxException { + 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); @@ -1714,13 +1818,13 @@ public class Uri { } private static void validateAuthority(final Encoded uri, final Encoded authority, final int index) throws URISyntaxException { - final int errIdx = validateEncoded(authority, AUTHORITY_LEGAL); + 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 Encoded path, final int index) throws URISyntaxException { + 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); @@ -1728,14 +1832,14 @@ public class Uri { } private static void validateQuery(final Encoded uri, final Encoded query, final int index) throws URISyntaxException { - final int errIdx = validateEncoded(query, QUERY_LEGAL); + 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, FRAG_LEGAL); + final int errIdx = validateEncoded(fragment.get(), FRAG_LEGAL); if( 0 <= errIdx ) { fail(uri, "invalid fragment", index+errIdx); } @@ -1802,10 +1906,10 @@ public class Uri { return false; } String label = null; - final StringTokenizer st = new StringTokenizer(hostS, "."); //$NON-NLS-1$ + final StringTokenizer st = new StringTokenizer(hostS, "."); while (st.hasMoreTokens()) { label = st.nextToken(); - if (label.startsWith("-") || label.endsWith("-")) { //$NON-NLS-1$ //$NON-NLS-2$ + if (label.startsWith("-") || label.endsWith("-")) { return false; } } @@ -1854,7 +1958,7 @@ public class Uri { boolean doubleColon = false; int numberOfColons = 0; int numberOfPeriods = 0; - String word = ""; //$NON-NLS-1$ + String word = ""; char c = 0; char prevChar = 0; int offset = 0; // offset for [] ip addresses @@ -1876,8 +1980,8 @@ public class Uri { if (ipv6Address.charAt(length - 1) != ']') { return false; // must have a close ] } - if ((ipv6Address.charAt(1) == IOUtil.SCHEME_SEPARATOR_CHAR) - && (ipv6Address.charAt(2) != IOUtil.SCHEME_SEPARATOR_CHAR)) { + if ((ipv6Address.charAt(1) == SCHEME_SEPARATOR) + && (ipv6Address.charAt(2) != SCHEME_SEPARATOR)) { return false; } offset = 1; @@ -1913,14 +2017,14 @@ public class Uri { // with // an IPv4 ending, otherwise 7 :'s is bad if (numberOfColons == 7 - && ipv6Address.charAt(0 + offset) != IOUtil.SCHEME_SEPARATOR_CHAR - && ipv6Address.charAt(1 + offset) != IOUtil.SCHEME_SEPARATOR_CHAR) { + && ipv6Address.charAt(0 + offset) != SCHEME_SEPARATOR + && ipv6Address.charAt(1 + offset) != SCHEME_SEPARATOR) { return false; } - word = ""; //$NON-NLS-1$ + word = ""; break; - case IOUtil.SCHEME_SEPARATOR_CHAR: + case SCHEME_SEPARATOR: numberOfColons++; if (numberOfColons > 7) { return false; @@ -1928,13 +2032,13 @@ public class Uri { if (numberOfPeriods > 0) { return false; } - if (prevChar == IOUtil.SCHEME_SEPARATOR_CHAR) { + if (prevChar == SCHEME_SEPARATOR) { if (doubleColon) { return false; } doubleColon = true; } - word = ""; //$NON-NLS-1$ + word = ""; break; default: @@ -1963,8 +2067,8 @@ public class Uri { // 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) != IOUtil.SCHEME_SEPARATOR_CHAR //$NON-NLS-1$ - && ipv6Address.charAt(length - 2 - offset) != IOUtil.SCHEME_SEPARATOR_CHAR) { + if (word == "" && ipv6Address.charAt(length - 1 - offset) != SCHEME_SEPARATOR + && ipv6Address.charAt(length - 2 - offset) != SCHEME_SEPARATOR) { return false; } } @@ -2005,7 +2109,7 @@ public class Uri { * {@code java.lang.String} the characters allowed in the String * s */ - private static int validateEncoded(final Encoded encoded, final String legal) { + 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 == '%') { 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 7a5b7ec..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; @@ -60,23 +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 char SCHEME_SEPARATOR_CHAR = ':'; - /** {@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 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 keyjava.io.tmpdir
. */ private static final String java_io_tmpdir_propkey = "java.io.tmpdir"; private static final String user_home_propkey = "user.home"; @@ -295,7 +277,6 @@ public class IOUtil { */ private static final Pattern patternSingleBS = Pattern.compile("\\\\{1}"); - private static final Pattern patternSingleFS = Pattern.compile("/{1}"); /** * @@ -424,67 +405,6 @@ public class IOUtil { return fname; } - /** - * The URI'sprotocol:/some/path/gluegen-rt.jar
- * parent dirname URIprotocol:/some/path/
will be returned. - *- * protocol may be "file", "http", etc.. - *
- * - * @param uri "protocol:/some/path/gluegen-rt.jar" - * @return "protocol:/some/path/" - * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null - * @throws URISyntaxException - * @deprecated Use {@link Uri#getDirectory()} - */ - 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'sprotocol:/some/path/gluegen-rt.jar
- * parent dirname URIprotocol:/some/path/
will be returned. - *- * protocol may be "file", "http", etc.. - *
- * - * @param uri "protocol:/some/path/gluegen-rt.jar" (URI encoded) - * @return "protocol:/some/path/" - * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null - * @throws URISyntaxException - * @deprecated Use {@link Uri#getDirectory()} - */ - 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("getURIDirname res: "+uriS); - } - return uriS; - } - /*** * * RESOURCE LOCATION STUFF @@ -615,6 +535,20 @@ public class IOUtil { return null; } + /** + * 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'. * @@ -698,31 +632,19 @@ public class IOUtil { ** Otherwise it returns the {@link URI#toASCIIString()} encoded URI. *
- * @deprecated Use {@link Uri#getNativeFilePath()}. + * @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 329ea51..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; @@ -112,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"com.jogamp.common.GlueGenVersion"
- * URIjar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"
+ * Urijar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"
* will be returned. ** sub_protocol may be "file", "http", etc.. @@ -132,108 +131,107 @@ public class JarUtil { * @param clazzBinName "com.jogamp.common.GlueGenVersion" * @param cl ClassLoader to locate the JarFile * @return "jar:sub_protocol:/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
jar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
+ * The Class's Jar Urijar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
* Jar basenamegluegen-rt.jar
will be returned. ** sub_protocol may be "file", "http", etc.. *
* - * @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.jar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
* @returngluegen-rt.jar
- * @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'scom.jogamp.common.GlueGenVersion
- * URIjar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
+ * Urijar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
* Jar basenamegluegen-rt.jar
will be returned. ** sub_protocol may be "file", "http", etc.. @@ -242,120 +240,54 @@ public class JarUtil { * @param clazzBinName
com.jogamp.common.GlueGenVersion
* @param cl * @returngluegen-rt.jar
- * @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 URIjar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
- * Jar file's sub URIsub_protocol:/some/path/gluegen-rt.jar
will be returned. - *- * sub_protocol may be "file", "http", etc.. - *
- * - * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()}, - * i.e.jar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
- * @returnsub_protocol:/some/path/gluegen-rt.jar
- * @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)} - * @deprecated Use {@link Uri#getContainedUri()} and validate it's scheme, etc. - */ - 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 URIjar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
+ * The Class's Jar Urijar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
* Jar file's entry/com/jogamp/common/GlueGenVersion.class
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.jar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
* @return/com/jogamp/common/GlueGenVersion.class
* @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'scom.jogamp.common.GlueGenVersion
- * URIjar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
- * Jar file's sub URIsub_protocol:/some/path/gluegen-rt.jar
will be returned. - *- * sub_protocol may be "file", "http", etc.. - *
- * - * @param clazzBinNamecom.jogamp.common.GlueGenVersion
- * @param cl - * @returnsub_protocol:/some/path/gluegen-rt.jar
- * @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"com.jogamp.common.GlueGenVersion"
- * URIjar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"
- * Jar file URIjar:sub_protocol:/some/path/gluegen-rt.jar!/
will be returned. + * Urijar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"
+ * Jar file Urijar:sub_protocol:/some/path/gluegen-rt.jar!/
will be returned. ** sub_protocol may be "file", "http", etc.. *
@@ -363,34 +295,35 @@ public class JarUtil { * @param clazzBinName "com.jogamp.common.GlueGenVersion" * @param cl * @return "jar:sub_protocol:/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+"!/"); } /** @@ -399,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); } /** @@ -439,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()); } @@ -480,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. ** class's jar url path + cutOffInclSubDir + relResPath, *@@ -502,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 cut off 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 8979a43..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; @@ -40,7 +39,6 @@ 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; @@ -69,9 +67,9 @@ public class TempJarCache { } // Set of jar files added - private static MapnativeLibJars; - private static Map classFileJars; - private static Map resourceFileJars; + private static Map nativeLibJars; + private static Map classFileJars; + private static Map resourceFileJars; private static TempFileCache tmpFileCache; @@ -97,9 +95,9 @@ public class TempJarCache { if(!staticInitError) { // Initialize the collections of resources nativeLibMap = new HashMap (); - nativeLibJars = new HashMap (); - classFileJars = new HashMap (); - resourceFileJars = new HashMap (); + nativeLibJars = new HashMap (); + classFileJars = new HashMap (); + resourceFileJars = new HashMap (); } if(DEBUG) { System.err.println("TempJarCache.initSingleton(): ok "+(false==staticInitError)+", "+ tmpFileCache.getTempDir()); @@ -183,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 jarURI
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 thejarUri
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"); } /** @@ -248,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 thejarURI
could not be loaded or a previous load attempt failed + * @param jarUri + * @throws IOException if thejarUri
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 thejarURI
could not be loaded or a previous load attempt failed + * @throws IOException if thejarUri
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"); } } @@ -309,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 thejarURI
could not be loaded or a previous load attempt failed + * @param jarUri + * @throws IOException if thejarUri
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) ) { @@ -333,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, @@ -352,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"); } } @@ -408,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 Uri.valueOf(f).toURI(); + return Uri.valueOf(f); } return null; } diff --git a/src/junit/com/jogamp/common/net/TestUri01.java b/src/junit/com/jogamp/common/net/TestUri01.java index 652caa6..bcc7d27 100644 --- a/src/junit/com/jogamp/common/net/TestUri01.java +++ b/src/junit/com/jogamp/common/net/TestUri01.java @@ -4,16 +4,12 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; - -import jogamp.common.os.PlatformPropsImpl; import org.junit.Assert; import org.junit.Test; import com.jogamp.common.net.URIDumpUtil; -import com.jogamp.common.os.Platform; +import com.jogamp.common.util.IOUtil; import com.jogamp.junit.util.JunitTracer; import org.junit.FixMethodOrder; @@ -23,7 +19,66 @@ import org.junit.runners.MethodSorters; public class TestUri01 extends JunitTracer { @Test - public void test00URIEscapeSpecialChars() throws IOException, URISyntaxException { + public void test00BasicCoding() throws IOException, URISyntaxException { + final String string = "Hallo Welt öä"; + System.err.println("sp1 "+string); + final File file = new File(string); + System.err.println("file "+file); + System.err.println("file.path.dec "+file.getPath()); + System.err.println("file.path.abs "+file.getAbsolutePath()); + System.err.println("file.path.can "+file.getCanonicalPath()); + final Uri uri0 = Uri.valueOf(file); + URIDumpUtil.showUri(uri0); + URIDumpUtil.showReencodedURIOfUri(uri0); + + boolean ok = true; + { + final String s2 = IOUtil.slashify(file.getAbsolutePath(), true /* startWithSlash */, file.isDirectory() /* endWithSlash */); + System.err.println("uri2.slashify: "+s2); + final Uri uri1 = Uri.create(Uri.FILE_SCHEME, null, s2, null); + final boolean equalEncoded= uri0.getEncoded().equals(uri1.getEncoded()); + final boolean equalPath = uri0.path.decode().equals(uri1.path.decode()); + final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString().get()); + System.err.println("uri2.enc : "+uri1.getEncoded()+" - "+(equalEncoded?"OK":"ERROR")); + System.err.println("uri2.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR")); + System.err.println("uri2.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); + ok = equalEncoded && equalPath && equalASCII && ok; + } + { + final String s2 = "/"+string; + System.err.println("uri3.orig: "+s2); + final Uri uri1 = Uri.create(Uri.FILE_SCHEME, s2, null); + final String rString = "file:/Hallo%20Welt%20öä"; + final String rPath = s2; + final String rASCII = "file:/Hallo%20Welt%20%C3%B6%C3%A4"; + final boolean equalEncoded = rString.equals(uri1.toString()); + final boolean equalPath = rPath.equals(uri1.path.decode()); + final boolean equalASCII= rASCII.equals(uri1.toASCIIString().get()); + System.err.println("uri3.enc : "+uri1.toString()+" - "+(equalEncoded?"OK":"ERROR")); + System.err.println("uri3.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR")); + System.err.println("uri3.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); + ok = equalEncoded && equalPath && equalASCII && ok; + } + { + final String s2 = "//lala.org/"+string; + System.err.println("uri4.orig: "+s2); + final Uri uri1 = Uri.create(Uri.HTTP_SCHEME, s2, null); + final String rString = "http://lala.org/Hallo%20Welt%20öä"; + final String rPath = "/"+string; + final String rASCII = "http://lala.org/Hallo%20Welt%20%C3%B6%C3%A4"; + final boolean equalString= rString.equals(uri1.toString()); + final boolean equalPath = rPath.equals(uri1.path.decode()); + final boolean equalASCII= rASCII.equals(uri1.toASCIIString().get()); + System.err.println("uri4.enc : "+uri1.toString()+" - "+(equalString?"OK":"ERROR")); + System.err.println("uri4.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR")); + System.err.println("uri4.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR")); + ok = equalString && equalPath && equalASCII && ok; + } + Assert.assertTrue("One or more errors occured see stderr above", ok); + } + + @Test + public void test02URIEscapeSpecialChars() throws IOException, URISyntaxException { { final String vanilla = "XXX ! # $ & ' ( ) * + , / : ; = ? @ [ ]"; final Uri.Encoded escaped = Uri.Encoded.cast("XXX%20!%20%23%20%24%20%26%20%27%20%28%20%29%20%2A%20%2B%20%2C%20/%20%3A%20%3B%20%3D%20%3F%20%40%20%5B%20%5D"); @@ -60,7 +115,7 @@ public class TestUri01 extends JunitTracer { } } @Test - public void test01URIEscapeCommonChars() throws IOException, URISyntaxException { + public void test03URIEscapeCommonChars() throws IOException, URISyntaxException { { final String vanilla = "/XXX \"%-.<>\\^_`{|}~"; final Uri.Encoded escaped = Uri.Encoded.cast("/XXX%20%22%25-.%3C%3E%5C%5E_%60%7B%7C%7D~"); @@ -95,16 +150,16 @@ public class TestUri01 extends JunitTracer { URIDumpUtil.showURI(uri3); System.err.println("URI -> Uri (keep encoding):"); - final Uri uri4 = Uri.valueOf(uri3, false); + final Uri uri4 = Uri.valueOf(uri3); URIDumpUtil.showUri(uri4); System.err.println("URI -> Uri (re-encode):"); - final Uri uri5 = Uri.valueOf(uri3, true); + final Uri uri5 = Uri.valueOf(uri3); URIDumpUtil.showUri(uri5); } @Test - public void test03EqualsAndHashCode() throws IOException, URISyntaxException { + public void test04EqualsAndHashCode() throws IOException, URISyntaxException { { final Uri uri0 = Uri.cast("http://localhost/test01.html#tag01"); final Uri uri1 = Uri.create("http", null, "localhost", -1, "/test01.html", null, "tag01"); @@ -155,7 +210,7 @@ public class TestUri01 extends JunitTracer { } @Test - public void test04ContainedUri() throws IOException, URISyntaxException { + public void test05Contained() throws IOException, URISyntaxException { { final Uri input = Uri.cast("http://localhost/test01.html#tag01"); final Uri contained = input.getContainedUri(); @@ -185,7 +240,7 @@ public class TestUri01 extends JunitTracer { } @Test - public void test05ParentUri() throws IOException, URISyntaxException { + public void test06ParentAndDir() throws IOException, URISyntaxException { { final Uri input = Uri.cast("http://localhost/"); final Uri parent = input.getParent(); @@ -193,167 +248,58 @@ public class TestUri01 extends JunitTracer { } { final Uri input = Uri.cast("jar:http://localhost/test01.jar!/com/Lala.class"); - final Uri expected1 = Uri.cast("jar:http://localhost/test01.jar!/com/"); - final Uri expected2 = Uri.cast("jar:http://localhost/test01.jar!/"); - final Uri expected3 = Uri.cast("jar:http://localhost/"); + final Uri expParen1 = Uri.cast("jar:http://localhost/test01.jar!/com/"); + final Uri expFolde1 = expParen1; + final Uri expParen2 = Uri.cast("jar:http://localhost/test01.jar!/"); + final Uri expFolde2 = expParen1; // is folder already + final Uri expParen3 = Uri.cast("jar:http://localhost/"); + final Uri expFolde3 = expParen2; // is folder already + Assert.assertNotEquals(input, expParen1); + Assert.assertNotEquals(expParen1, expParen2); + Assert.assertNotEquals(expParen1, expParen3); + final Uri parent1 = input.getParent(); + final Uri folder1 = input.getDirectory(); final Uri parent2 = parent1.getParent(); + final Uri folder2 = parent1.getDirectory(); final Uri parent3 = parent2.getParent(); - Assert.assertEquals(expected1, parent1); - Assert.assertEquals(expected1.hashCode(), parent1.hashCode()); - Assert.assertEquals(expected2, parent2); - Assert.assertEquals(expected2.hashCode(), parent2.hashCode()); - Assert.assertEquals(expected3, parent3); - Assert.assertEquals(expected3.hashCode(), parent3.hashCode()); - } - { - final Uri input = Uri.cast("http://localhost/dir/test01.jar?lala=01#frag01"); - final Uri expected1 = Uri.cast("http://localhost/dir/"); - final Uri expected2 = Uri.cast("http://localhost/"); - final Uri parent1 = input.getParent(); - final Uri parent2 = parent1.getParent(); - Assert.assertEquals(expected1, parent1); - Assert.assertEquals(expected1.hashCode(), parent1.hashCode()); - Assert.assertEquals(expected2, parent2); - Assert.assertEquals(expected2.hashCode(), parent2.hashCode()); - } - } + final Uri folder3 = parent2.getDirectory(); - @Test - public void test10HttpUri2URL() throws IOException, URISyntaxException { - testUri2URL(getSimpleTestName("."), TestUri03Resolving.uriHttpSArray); - } + Assert.assertEquals(expParen1, parent1); + Assert.assertEquals(expParen1.hashCode(), parent1.hashCode()); + Assert.assertEquals(expFolde1, folder1); - @Test - public void test20FileUnixUri2URL() throws IOException, URISyntaxException { - testUri2URL(getSimpleTestName("."), TestUri03Resolving.uriFileSArrayUnix); - } + Assert.assertEquals(expParen2, parent2); + Assert.assertEquals(expParen2.hashCode(), parent2.hashCode()); + Assert.assertEquals(expFolde2, folder2); - @Test - public void test21FileWindowsUri2URL() throws IOException, URISyntaxException { - testUri2URL(getSimpleTestName("."), TestUri03Resolving.uriFileSArrayWindows); - } - - @Test - public void test30FileUnixUri2URL() throws IOException, URISyntaxException { - if( Platform.OSType.WINDOWS != PlatformPropsImpl.OS_TYPE ) { - testFile2Uri(getSimpleTestName("."), TestUri03Resolving.fileSArrayUnix); - } - } - - @Test - public void test31FileWindowsUri2URL() throws IOException, URISyntaxException { - if( Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE ) { - testFile2Uri(getSimpleTestName("."), TestUri03Resolving.fileSArrayWindows); - } - } + Assert.assertEquals(expParen3, parent3); + Assert.assertEquals(expParen3.hashCode(), parent3.hashCode()); + Assert.assertEquals(expFolde3, folder3); - static void testUri2URL(final String testname, final String[][] uriSArray) throws IOException, URISyntaxException { - boolean ok = true; - for(int i=0; i[1] // "A$-B%5E-C~-D%23-E]-F[-%C3%B6%C3%A4/"); <- '[' ']' -> [2] - "A$-B%5E-C~-D%23-E%5D-F%5B-%C3%B6%C3%A4/"); + // "A$-B%5E-C~-D%23-E%5D-F%5B-%C3%B6%C3%A4/"); /** * [1] '#' java.lang.IllegalArgumentException: URI has a fragment component @@ -111,34 +110,35 @@ public class TestUri99LaunchOnReservedCharPathBug908 extends JunitTracer { */ } - private void testTempJarCacheOddJarPathImpl(final String subPathUTF, final String subPathEncoded) throws IOException, IllegalArgumentException, URISyntaxException { + private void testTempJarCacheOddJarPathImpl(final String subPathUTF) throws IOException, IllegalArgumentException, URISyntaxException { if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; } + final Uri.Encoded subPathEncoded = new Uri.Encoded(subPathUTF, Uri.PATH_LEGAL); final String reservedCharPathUnencoded = "test/build/"+getClass().getSimpleName()+"/"+getTestMethodName()+"/"+subPathUTF; - final String reservedCharPathEncoded = "test/build/"+getClass().getSimpleName()+"/"+getTestMethodName()+"/"+subPathEncoded; + final Uri.Encoded reservedCharPathEncoded = Uri.Encoded.cast("test/build/"+getClass().getSimpleName()+"/"+getTestMethodName()+"/").concat(subPathEncoded); System.err.println("0 Unencoded: "+reservedCharPathUnencoded); System.err.println("0 Encoded: "+reservedCharPathEncoded); // jar:file:/dir1/dir2/gluegen-rt.jar!/ - final URI jarFileURI = JarUtil.getJarFileURI(Platform.class.getName(), getClass().getClassLoader()); + final Uri jarFileURI = JarUtil.getJarFileUri(Platform.class.getName(), getClass().getClassLoader()); System.err.println("1 jarFileURI: "+jarFileURI.toString()); // gluegen-rt.jar - final String jarBasename = JarUtil.getJarBasename(jarFileURI); + final Uri.Encoded jarBasename = JarUtil.getJarBasename(jarFileURI); System.err.println("2 jarBasename: "+jarBasename); // file:/dir1/build/gluegen-rt.jar - final URI fileURI = JarUtil.getJarSubURI(jarFileURI); + final Uri fileURI = jarFileURI.getContainedUri(); System.err.println("3 fileURI: "+fileURI.toString()); // file:/dir1/build/ - final URI fileFolderURI = new URI(IOUtil.getParentOf(fileURI.toString())); + final Uri fileFolderURI = fileURI.getParent(); System.err.println("4 fileFolderURI: "+fileFolderURI.toString()); // file:/dir1/build/test/build/A$-B^-C~-D#-E]-F[/ - final URI fileNewFolderURI = new URI(fileFolderURI.toString()+reservedCharPathEncoded); + final Uri fileNewFolderURI = fileFolderURI.concat(reservedCharPathEncoded); System.err.println("5 fileNewFolderURI: "+fileNewFolderURI.toString()); - final File srcFolder = new File(fileFolderURI); - final File dstFolder = new File(fileNewFolderURI); + final File srcFolder = fileFolderURI.toFile(); + final File dstFolder = fileNewFolderURI.toFile(); System.err.println("6 srcFolder: "+srcFolder.toString()); System.err.println("7 dstFolder: "+dstFolder.toString()); try { diff --git a/src/junit/com/jogamp/common/net/URIDumpUtil.java b/src/junit/com/jogamp/common/net/URIDumpUtil.java index a7d050a..c5ba51f 100644 --- a/src/junit/com/jogamp/common/net/URIDumpUtil.java +++ b/src/junit/com/jogamp/common/net/URIDumpUtil.java @@ -52,7 +52,7 @@ public class URIDumpUtil { System.err.println("0.0.0 string: "+uri.toString()); System.err.println("0.0.0 ascii : "+uri.toASCIIString()); - System.err.println("0.0.0 native-file: "+uri.getNativeFilePath()); + System.err.println("0.0.0 native-file: "+uri.toFile()); System.err.println("0.0.0 contained: "+uri.getContainedUri()); System.err.println("1.0.0 scheme: "+uri.scheme); @@ -73,7 +73,7 @@ public class URIDumpUtil { * @throws URISyntaxException */ public static void showReencodedURIOfUri(final Uri uri) throws URISyntaxException { - final URI recomposedURI = uri.toURI(true); + final URI recomposedURI = uri.toURIReencoded(); showURI("YYYYYY Recomposed URI "+recomposedURI+", isOpaque "+recomposedURI.isOpaque()+", isAbs "+recomposedURI.isAbsolute(), recomposedURI); final String recomposedURIStr = recomposedURI.toString(); final boolean equalsRecompURI = uri.input.equals(recomposedURIStr); @@ -88,7 +88,7 @@ public class URIDumpUtil { * @throws URISyntaxException */ public static void showReencodedUriOfURI(final URI uri) throws URISyntaxException { - final Uri recomposedUri = Uri.valueOf(uri, true); + final Uri recomposedUri = Uri.valueOf(uri); showUri("ZZZZZZ Recomposed Uri "+recomposedUri+", isOpaque "+recomposedUri.opaque+", isAbs "+recomposedUri.absolute+", hasAuth "+recomposedUri.hasAuthority, recomposedUri); final String recomposedUriStr = recomposedUri.toString(); final boolean equalsRecompUri = uri.toString().equals(recomposedUriStr); diff --git a/src/junit/com/jogamp/common/util/TestJarUtil.java b/src/junit/com/jogamp/common/util/TestJarUtil.java index db5c268..06a2e43 100644 --- a/src/junit/com/jogamp/common/util/TestJarUtil.java +++ b/src/junit/com/jogamp/common/util/TestJarUtil.java @@ -30,7 +30,6 @@ package com.jogamp.common.util; import java.io.IOException; import java.net.MalformedURLException; -import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; @@ -46,6 +45,8 @@ import org.junit.BeforeClass; import org.junit.Test; import com.jogamp.common.GlueGenVersion; +import com.jogamp.common.net.URIDumpUtil; +import com.jogamp.common.net.Uri; import com.jogamp.common.os.AndroidVersion; import com.jogamp.common.util.cache.TempCacheReg; import com.jogamp.common.util.cache.TempFileCache; @@ -97,7 +98,7 @@ public class TestJarUtil extends JunitTracer { } } - void validateJarFileURL(final URI jarFileURI) throws IllegalArgumentException, IOException, URISyntaxException { + void validateJarFileURL(final Uri jarFileURI) throws IllegalArgumentException, IOException, URISyntaxException { Assert.assertNotNull(jarFileURI); final URL jarFileURL = jarFileURI.toURL(); final URLConnection aURLc = jarFileURL.openConnection(); @@ -110,18 +111,27 @@ public class TestJarUtil extends JunitTracer { } void validateJarUtil(final String expJarName, final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException { - final String jarName= JarUtil.getJarBasename(clazzBinName, cl); + final Uri.Encoded expJarNameE = Uri.Encoded.cast(expJarName); + final Uri.Encoded jarName= JarUtil.getJarBasename(clazzBinName, cl); Assert.assertNotNull(jarName); - Assert.assertEquals(expJarName, jarName); + Assert.assertEquals(expJarNameE, jarName); - final URI jarSubURI = JarUtil.getJarSubURI(clazzBinName, cl); - Assert.assertNotNull(jarSubURI); - final URL jarSubURL= jarSubURI.toURL(); + final Uri jarUri = JarUtil.getJarUri(clazzBinName, cl); + Assert.assertNotNull(jarUri); + System.err.println("1 - jarUri:"); + URIDumpUtil.showUri(jarUri); + + final Uri jarSubUri = jarUri.getContainedUri(); + Assert.assertNotNull(jarSubUri); + System.err.println("2 - jarSubUri:"); + URIDumpUtil.showUri(jarSubUri); + + final URL jarSubURL= jarSubUri.toURL(); final URLConnection urlConn = jarSubURL.openConnection(); Assert.assertTrue("jarSubURL has zero content: "+jarSubURL, urlConn.getContentLength()>0); System.err.println("URLConnection of jarSubURL: "+urlConn); - final URI jarFileURL = JarUtil.getJarFileURI(clazzBinName, cl); + final Uri jarFileURL = JarUtil.getJarFileUri(clazzBinName, cl); validateJarFileURL(jarFileURL); final JarFile jarFile = JarUtil.getJarFile(clazzBinName, cl); @@ -146,10 +156,10 @@ public class TestJarUtil extends JunitTracer { final ClassLoader rootCL = this.getClass().getClassLoader(); // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache - TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI("ClassInJar0", rootCL)); + TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri("ClassInJar0", rootCL)); // Fetch and load the contained "ClassInJar1.jar" - final URL ClassInJar1_jarFileURL = JarUtil.getJarFileURI(TempJarCache.getResource("ClassInJar1.jar")).toURL(); + final URL ClassInJar1_jarFileURL = JarUtil.getJarFileUri(TempJarCache.getResourceUri("ClassInJar1.jar")).toURL(); final ClassLoader cl = new URLClassLoader(new URL[] { ClassInJar1_jarFileURL }, rootCL); Assert.assertNotNull(cl); validateJarUtil("ClassInJar1.jar", "ClassInJar1", cl); @@ -167,10 +177,10 @@ public class TestJarUtil extends JunitTracer { final ClassLoader rootCL = this.getClass().getClassLoader(); // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache - TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI("ClassInJar0", rootCL)); + TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri("ClassInJar0", rootCL)); // Fetch and load the contained "ClassInJar1.jar" - final URL ClassInJar2_jarFileURL = JarUtil.getJarFileURI(TempJarCache.getResource("sub/ClassInJar2.jar")).toURL(); + final URL ClassInJar2_jarFileURL = JarUtil.getJarFileUri(TempJarCache.getResourceUri("sub/ClassInJar2.jar")).toURL(); final ClassLoader cl = new URLClassLoader(new URL[] { ClassInJar2_jarFileURL }, rootCL); Assert.assertNotNull(cl); validateJarUtil("ClassInJar2.jar", "ClassInJar2", cl); @@ -231,7 +241,7 @@ public class TestJarUtil extends JunitTracer { public URL resolve( final URL url ) { if( url.getProtocol().equals("bundleresource") ) { try { - return new URL( IOUtil.JAR_SCHEME, "", url.getFile() ); + return new URL( Uri.JAR_SCHEME, "", url.getFile() ); } catch(final MalformedURLException e) { return url; } @@ -244,10 +254,10 @@ public class TestJarUtil extends JunitTracer { final ClassLoader rootCL = new CustomClassLoader(); // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache - TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI("ClassInJar0", rootCL)); + TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri("ClassInJar0", rootCL)); // Fetch and load the contained "ClassInJar1.jar" - final URL ClassInJar2_jarFileURL = JarUtil.getJarFileURI(TempJarCache.getResource("sub/ClassInJar2.jar")).toURL(); + final URL ClassInJar2_jarFileURL = JarUtil.getJarFileUri(TempJarCache.getResourceUri("sub/ClassInJar2.jar")).toURL(); final ClassLoader cl = new URLClassLoader(new URL[] { ClassInJar2_jarFileURL }, rootCL); Assert.assertNotNull(cl); validateJarUtil("ClassInJar2.jar", "ClassInJar2", cl); diff --git a/src/junit/com/jogamp/common/util/TestTempJarCache.java b/src/junit/com/jogamp/common/util/TestTempJarCache.java index cd825fe..474a17a 100644 --- a/src/junit/com/jogamp/common/util/TestTempJarCache.java +++ b/src/junit/com/jogamp/common/util/TestTempJarCache.java @@ -31,7 +31,6 @@ package com.jogamp.common.util; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; -import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; @@ -44,6 +43,8 @@ import org.junit.Test; import org.junit.runners.MethodSorters; import com.jogamp.common.GlueGenVersion; +import com.jogamp.common.net.URIDumpUtil; +import com.jogamp.common.net.Uri; import com.jogamp.common.os.AndroidVersion; import com.jogamp.common.os.NativeLibrary; import com.jogamp.common.os.Platform; @@ -175,7 +176,7 @@ public class TestTempJarCache extends JunitTracer { if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; } final ClassLoader cl = getClass().getClassLoader(); - TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI(GlueGenVersion.class.getName(), cl)); + TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri(GlueGenVersion.class.getName(), cl)); File f0 = new File(TempJarCache.getTempFileCache().getTempDir(), "META-INF/MANIFEST.MF"); Assert.assertTrue(f0.exists()); @@ -195,14 +196,28 @@ public class TestTempJarCache extends JunitTracer { @Test public void testTempJarCache02AddNativeLibs() throws IOException, IllegalArgumentException, URISyntaxException { if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; } - final String nativeJarName = "gluegen-rt-natives-"+Platform.getOSAndArch()+".jar"; + final Uri.Encoded nativeJarName = Uri.Encoded.cast("gluegen-rt-natives-"+Platform.getOSAndArch()+".jar"); final String libBaseName = "gluegen-rt"; final ClassLoader cl = getClass().getClassLoader(); - URI jarUriRoot = JarUtil.getJarSubURI(TempJarCache.class.getName(), cl); - jarUriRoot = IOUtil.getURIDirname(jarUriRoot); + final Uri jarUri = JarUtil.getJarUri(TempJarCache.class.getName(), cl); + Assert.assertNotNull(jarUri); + System.err.println("1 - jarUri:"); + URIDumpUtil.showUri(jarUri); - final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName); + final Uri jarFileUri = jarUri.getContainedUri(); + Assert.assertNotNull(jarFileUri); + System.err.println("2 - jarFileUri:"); + URIDumpUtil.showUri(jarFileUri); + + final Uri jarFileDir = jarFileUri.getParent(); + Assert.assertNotNull(jarFileDir); + System.err.println("3 - jarFileDir:"); + URIDumpUtil.showUri(jarFileDir); + + final Uri nativeJarURI = JarUtil.getJarFileUri(jarFileDir, nativeJarName); + System.err.println("4 - nativeJarURI:"); + URIDumpUtil.showUri(nativeJarURI); TempJarCache.addNativeLibs(TempJarCache.class, nativeJarURI, null /* nativeLibraryPath */); final String libFullPath = TempJarCache.findLibrary(libBaseName); @@ -225,7 +240,7 @@ public class TestTempJarCache extends JunitTracer { @Test public void testTempJarCache04bDiffClassLoader() throws IOException, IllegalArgumentException, URISyntaxException { if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; } - final URL[] urls = new URL[] { JarUtil.getJarFileURI(TempJarCache.class.getName(), getClass().getClassLoader()).toURL() }; + final URL[] urls = new URL[] { JarUtil.getJarFileUri(TempJarCache.class.getName(), getClass().getClassLoader()).toURL() }; System.err.println("url: "+urls[0]); final ClassLoader cl2 = new TestClassLoader(urls, null); final ClassLoader cl3 = new TestClassLoader(urls, null); diff --git a/src/junit/com/jogamp/junit/sec/Applet01.java b/src/junit/com/jogamp/junit/sec/Applet01.java index a335efe..f0188a2 100644 --- a/src/junit/com/jogamp/junit/sec/Applet01.java +++ b/src/junit/com/jogamp/junit/sec/Applet01.java @@ -34,14 +34,13 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URISyntaxException; -import java.net.URL; import java.security.AccessControlException; +import com.jogamp.common.net.Uri; import com.jogamp.common.os.MachineDescription; import com.jogamp.common.os.NativeLibrary; import com.jogamp.common.os.Platform; import com.jogamp.common.util.IOUtil; -import com.jogamp.common.util.JarUtil; /** * Applet: Provoke AccessControlException while writing to file! @@ -156,64 +155,64 @@ public class Applet01 extends Applet { } } - private void testOpenLibrary(final boolean global) { + private void testOpenLibrary(final boolean global) throws URISyntaxException { final ClassLoader cl = getClass().getClassLoader(); System.err.println("CL "+cl); String libBaseName = null; final Class> clazz = this.getClass(); - URL libURL = clazz.getResource("/libtest1.so"); - if( null != libURL ) { + Uri libUri = null; + try { + libUri = Uri.valueOf(clazz.getResource("/libtest1.so")); + } catch (final URISyntaxException e2) { + // not found .. OK + } + if( null != libUri ) { libBaseName = "libtest1.so"; } else { - libURL = clazz.getResource("/test1.dll"); - if( null != libURL ) { - libBaseName = "test1.dll"; + try { + libUri = Uri.valueOf(clazz.getResource("/test1.dll")); + if( null != libUri ) { + libBaseName = "test1.dll"; + } + } catch (final URISyntaxException e) { + // not found } } - System.err.println("Untrusted Library (URL): "+libURL); + System.err.println("Untrusted Library (URL): "+libUri); - String libDir1 = null; - if( null != libURL ) { + if( null != libUri ) { + Uri libDir1 = libUri.getContainedUri(); + System.err.println("libDir1.1: "+libDir1); + libDir1= libDir1.getParent(); + System.err.println("libDir1.2: "+libDir1); + System.err.println("Untrusted Library Dir1 (abs): "+libDir1); + final Uri absLib = libDir1.concat(Uri.Encoded.cast("natives/" + libBaseName)); + Exception sec01 = null; try { - libDir1 = JarUtil.getJarSubURI(libURL.toURI()).getPath(); - } catch (final Exception e) { - e.printStackTrace(); - } - if( null != libDir1 ) { - System.err.println("libDir1.1: "+libDir1); - try { - libDir1= IOUtil.getParentOf(libDir1); - } catch (final URISyntaxException e) { - e.printStackTrace(); + final NativeLibrary nlib = NativeLibrary.open(absLib.toFile().getPath(), cl); + System.err.println("NativeLibrary: "+nlib); + } catch (final SecurityException e) { + sec01 = e; + if( usesSecurityManager ) { + System.err.println("Expected exception for loading native library"); + System.err.println("Message: "+sec01.getMessage()); + } else { + System.err.println("Unexpected exception for loading native library"); + sec01.printStackTrace(); } - System.err.println("libDir1.2: "+libDir1); } - } - System.err.println("Untrusted Library Dir1 (abs): "+libDir1); - final String absLib = libDir1 + "natives/" + libBaseName; - Exception sec01 = null; - try { - final NativeLibrary nlib = NativeLibrary.open(absLib, cl); - System.err.println("NativeLibrary: "+nlib); - } catch (final SecurityException e) { - sec01 = e; - if( usesSecurityManager ) { - System.err.println("Expected exception for loading native library"); - System.err.println("Message: "+sec01.getMessage()); + if( !usesSecurityManager ) { + if( null != sec01 ) { + throw new Error("SecurityException thrown on loading native library", sec01); + } } else { - System.err.println("Unexpected exception for loading native library"); - sec01.printStackTrace(); - } - } - if( !usesSecurityManager ) { - if( null != sec01 ) { - throw new Error("SecurityException thrown on loading native library", sec01); + if( null == sec01 ) { + throw new Error("SecurityException not thrown on loading native library"); + } } } else { - if( null == sec01 ) { - throw new Error("SecurityException not thrown on loading native library"); - } + System.err.println("No library found"); } } @@ -244,7 +243,11 @@ public class Applet01 extends Applet { testWriteFile(); System.err.println("writeFile: OK"); - testOpenLibrary(true); + try { + testOpenLibrary(true); + } catch (final URISyntaxException e) { + e.printStackTrace(); + } System.err.println("lib0: OK"); } diff --git a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java index e4e1b34..b347680 100644 --- a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java +++ b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java @@ -29,7 +29,6 @@ package com.jogamp.junit.sec; import java.net.URISyntaxException; -import java.net.URL; import java.security.AccessControlException; import java.io.File; import java.io.IOException; @@ -38,10 +37,10 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import com.jogamp.common.net.Uri; import com.jogamp.common.os.NativeLibrary; import com.jogamp.common.os.Platform; import com.jogamp.common.util.IOUtil; -import com.jogamp.common.util.JarUtil; import com.jogamp.junit.util.JunitTracer; import org.junit.FixMethodOrder; @@ -137,73 +136,75 @@ public class TestSecIOUtil01 extends JunitTracer { testTempDirImpl(false); } - private NativeLibrary openLibraryImpl(final boolean global) { + private NativeLibrary openLibraryImpl(final boolean global) throws URISyntaxException { final ClassLoader cl = getClass().getClassLoader(); System.err.println("CL "+cl); String libBaseName = null; final Class> clazz = this.getClass(); - URL libURL = clazz.getResource("/libtest1.so"); - if( null != libURL ) { + Uri libUri = null; + try { + libUri = Uri.valueOf(clazz.getResource("/libtest1.so")); + } catch (final URISyntaxException e2) { + // not found .. OK + } + if( null != libUri ) { libBaseName = "libtest1.so"; } else { - libURL = clazz.getResource("/test1.dll"); - if( null != libURL ) { - libBaseName = "test1.dll"; + try { + libUri = Uri.valueOf(clazz.getResource("/test1.dll")); + if( null != libUri ) { + libBaseName = "test1.dll"; + } + } catch (final URISyntaxException e) { + // not found } } - System.err.println("Untrusted Library (URL): "+libURL); - - String libDir1 = null; - if( null != libURL ) { + System.err.println("Untrusted Library (URL): "+libUri); + + if( null != libUri ) { + Uri libDir1 = libUri.getContainedUri(); + System.err.println("libDir1.1: "+libDir1); + libDir1= libDir1.getParent(); + System.err.println("libDir1.2: "+libDir1); + System.err.println("Untrusted Library Dir1 (abs): "+libDir1); + final Uri absLib = libDir1.concat(Uri.Encoded.cast("natives/" + libBaseName)); + Exception se0 = null; + NativeLibrary nlib = null; try { - libDir1 = JarUtil.getJarSubURI(libURL.toURI()).getPath(); - } catch (final Exception e) { - e.printStackTrace(); - } - if( null != libDir1 ) { - System.err.println("libDir1.1: "+libDir1); - try { - libDir1= IOUtil.getParentOf(libDir1); - } catch (final URISyntaxException e) { - e.printStackTrace(); + nlib = NativeLibrary.open(absLib.toFile().getPath(), cl); + System.err.println("NativeLibrary: "+nlib); + } catch (final SecurityException e) { + se0 = e; + if( usesSecurityManager ) { + System.err.println("Expected exception for loading native library"); + System.err.println("Message: "+se0.getMessage()); + } else { + System.err.println("Unexpected exception for loading native library"); + se0.printStackTrace(); } - System.err.println("libDir1.2: "+libDir1); } - } - System.err.println("Untrusted Library Dir1 (abs): "+libDir1); - final String absLib = libDir1 + "natives/" + libBaseName; - Exception se0 = null; - NativeLibrary nlib = null; - try { - nlib = NativeLibrary.open(absLib, cl); - System.err.println("NativeLibrary: "+nlib); - } catch (final SecurityException e) { - se0 = e; - if( usesSecurityManager ) { - System.err.println("Expected exception for loading native library"); - System.err.println("Message: "+se0.getMessage()); + if( !usesSecurityManager ) { + Assert.assertNull("SecurityException thrown on loading native library", se0); } else { - System.err.println("Unexpected exception for loading native library"); - se0.printStackTrace(); + Assert.assertNotNull("SecurityException not thrown on loading native library", se0); } - } - if( !usesSecurityManager ) { - Assert.assertNull("SecurityException thrown on loading native library", se0); + return nlib; } else { - Assert.assertNotNull("SecurityException not thrown on loading native library", se0); + System.err.println("No library found"); + return null; } - return nlib; + } - public void testOpenLibrary() { + public void testOpenLibrary() throws URISyntaxException { final NativeLibrary nlib = openLibraryImpl(true); if( null != nlib ) { nlib.close(); } } - public static void main(final String args[]) throws IOException { + public static void main(final String args[]) throws IOException, URISyntaxException { TestSecIOUtil01.setup(); final TestSecIOUtil01 aa = new TestSecIOUtil01(); diff --git a/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java b/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java index 953c795..78f4460 100644 --- a/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java +++ b/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java @@ -29,7 +29,6 @@ package com.jogamp.junit.util; import java.io.File; import java.io.IOException; -import java.net.URI; import java.net.URISyntaxException; import java.util.HashSet; import java.util.Set; @@ -40,7 +39,7 @@ import org.semver.Comparer; import org.semver.Delta; import org.semver.Dumper; -import com.jogamp.common.util.IOUtil; +import com.jogamp.common.net.Uri; import com.jogamp.common.util.JarUtil; import com.jogamp.common.util.VersionNumberString; @@ -54,12 +53,10 @@ public class VersionSemanticsUtil { throws IllegalArgumentException, IOException, URISyntaxException { // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache - final URI currentJarURI = JarUtil.getJarSubURI(currentJarClazz.getName(), currentJarCL); - final String currentJarLocS = IOUtil.decodeURIIfFilePath(currentJarURI); - final File currentJar = new File(currentJarLocS); + final Uri currentJarUri = JarUtil.getJarUri(currentJarClazz.getName(), currentJarCL).getContainedUri(); testVersion(diffCriteria, expectedCompatibilityType, previousJar, preVersionNumber, - currentJar, curVersionNumber, + currentJarUri.toFile(), curVersionNumber, excludesRegExp); } -- cgit v1.2.3