diff options
author | Sven Gothel <[email protected]> | 2013-06-19 04:44:14 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-06-19 04:44:14 +0200 |
commit | 4376174ad35fdaf76f59430328582e913f468674 (patch) | |
tree | eb1faa41eb440b1fec0c5f9932007050e5bd7e8b /src/java/com | |
parent | 88dca02541d96f68a892ae7824e9e1b29793ae55 (diff) |
Fix Bug 757: Regression of URL to URI conversion (Encoded path not compatible w/ file scheme.
Regression of (Bug 683, Commit b98825eb7cfb61aead4a7dff57471cd2d2c26823).
The URI encoded path cannot be read by File I/O (if file scheme), since the latter
requests an UTF8/16 name, not an URI encoded name (i.e. %20 for space).
The encoded URL is produced if calling 'uri.toURL()' and hence
the new 'IOUtil.toURL(URI)' provides a custom conversion recovering the UTF name via 'new File(uri).getPath()'.
Tested w/
- synthetic URI/URL coposition (unit test)
- manual w/ moving 'build' to 'build öä lala' for gluegen, joal and jogl.
+++
Misc.:
- 'URI JarUtil.getURIDirname(URI)' -> 'URI IOUtil.getDirname(URI)'
++
Diffstat (limited to 'src/java/com')
-rw-r--r-- | src/java/com/jogamp/common/jvm/JNILibLoaderBase.java | 3 | ||||
-rw-r--r-- | src/java/com/jogamp/common/os/Platform.java | 3 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/IOUtil.java | 109 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/JarUtil.java | 87 | ||||
-rw-r--r-- | src/java/com/jogamp/common/util/cache/TempJarCache.java | 20 |
5 files changed, 157 insertions, 65 deletions
diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java index 456c35a..2023162 100644 --- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java +++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java @@ -52,6 +52,7 @@ import java.util.Iterator; import java.util.List; import com.jogamp.common.os.NativeLibrary; +import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.JarUtil; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.cache.TempJarCache; @@ -155,7 +156,7 @@ public class JNILibLoaderBase { if(TempJarCache.isInitialized()) { final String nativeJarName = nativeJarBasename+"-natives-"+PlatformPropsImpl.os_and_arch+".jar"; msg.append(nativeJarName); - final URI jarUriRoot = JarUtil.getURIDirname( JarUtil.getJarSubURI( classJarURI ) ); + final URI jarUriRoot = IOUtil.getDirname( JarUtil.getJarSubURI( classJarURI ) ); msg.append(" + ").append(jarUriRoot); final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName); msg.append(" -> ").append(nativeJarURI); diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java index 0ae3cbb..9971cf4 100644 --- a/src/java/com/jogamp/common/os/Platform.java +++ b/src/java/com/jogamp/common/os/Platform.java @@ -33,6 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.TimeUnit; +import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.JarUtil; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.common.util.VersionNumber; @@ -198,7 +199,7 @@ public class Platform extends PlatformPropsImpl { final String jarName = JarUtil.getJarBasename( platformClassJarURI ); final String nativeJarBasename = jarName.substring(0, jarName.indexOf(".jar")); // ".jar" already validated w/ JarUtil.getJarBasename(..) nativeJarName = nativeJarBasename+"-natives-"+PlatformPropsImpl.os_and_arch+".jar"; - jarUriRoot = JarUtil.getURIDirname( JarUtil.getJarSubURI( platformClassJarURI ) ); + jarUriRoot = IOUtil.getDirname( JarUtil.getJarSubURI( platformClassJarURI ) ); nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName); TempJarCache.bootstrapNativeLib(Platform.class, libBaseName, nativeJarURI); } catch (Exception e0) { diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java index 2f0c77f..2c3c756 100644 --- a/src/java/com/jogamp/common/util/IOUtil.java +++ b/src/java/com/jogamp/common/util/IOUtil.java @@ -56,14 +56,22 @@ import com.jogamp.common.os.Platform; public class IOUtil { public static final boolean DEBUG = Debug.debug("IOUtil"); - public static final String JAR_SCHEME = "jar"; + /** {@value} */ + public static final String SCHEME_SEPARATOR = ":"; + /** {@value} */ public static final String FILE_SCHEME = "file"; + /** {@value} */ public static final String HTTP_SCHEME = "http"; + /** {@value} */ public static final String HTTPS_SCHEME = "https"; + /** {@value} */ + public static final String JAR_SCHEME = "jar"; + /** A JAR subprotocol is separeted from the JAR entry w/ this separator {@value}. Even if no class is specified '!/' must follow!. */ + public static final String JAR_SCHEME_SEPARATOR = "!"; - /** Std. temporary directory property key <code>java.io.tmpdir</code> */ - public static final String java_io_tmpdir_propkey = "java.io.tmpdir"; - public static final String user_home_propkey = "user.home"; + /** Std. temporary directory property key <code>java.io.tmpdir</code>. */ + private static final String java_io_tmpdir_propkey = "java.io.tmpdir"; + private static final String user_home_propkey = "user.home"; private static final String XDG_CACHE_HOME_envkey = "XDG_CACHE_HOME"; /** Subdirectory within platform's temporary root directory where all JogAmp related temp files are being stored: {@code jogamp} */ @@ -300,7 +308,7 @@ public class IOUtil { public static URI toURISimple(String protocol, String file, boolean isDirectory) throws URISyntaxException { return new URI(protocol, null, slashify(file, true, isDirectory), null); } - + /** * Returns the lowercase suffix of the given file name (the text * after the last '.' in the file name). Returns null if the file @@ -333,7 +341,14 @@ public class IOUtil { } return toLowerCase(filename.substring(lastDot + 1)); } + private static String toLowerCase(String arg) { + if (arg == null) { + return null; + } + return arg.toLowerCase(); + } + /*** * @param file * @param allowOverwrite @@ -402,14 +417,88 @@ public class IOUtil { return fname; } - private static String toLowerCase(String arg) { - if (arg == null) { - return null; + /** + * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code> + * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned. + * <p> + * <i>protocol</i> may be "file", "http", etc.. + * </p> + * + * @param uri "<i>protocol</i>:/some/path/gluegen-rt.jar" + * @return "<i>protocol</i>:/some/path/" + * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null + * @throws URISyntaxException + */ + public static URI getDirname(URI uri) throws IllegalArgumentException, URISyntaxException { + if(null == uri) { + throw new IllegalArgumentException("URI is null"); } - - return arg.toLowerCase(); + String uriS = uri.toString(); + if( DEBUG ) { + System.out.println("getURIDirname "+uri+", extForm: "+uriS); + } + // 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 <"+uri+">"); + } + } + uriS = uriS.substring(0, idx+1); // exclude jar name, include terminal '/' or ':' + + if( DEBUG ) { + System.out.println("getJarURIDirname res: "+uriS); + } + return new URI(uriS); } + /** + * Converts an {@link URI} to an {@link URL} while using a non encoded path + * for <i>file scheme</i>, i.e. <code>file:/</code>. + * Otherwise the default {@link URL} translation {@link URI#toURL()} is being used. + * <p> + * The folloing cases are considered: + * <ul> + * <li><i>file schema</i> is converted via <code>new File(uri).getPath()</code>.</li> + * <li><i>jar scheme</i> + * <ul> + * <li>subprotocol is being converted as above, if <i>file scheme</i>.</li> + * <li>JAR entry is not converted but preserved.</li> + * </ul></li> + * </ul> + * </p> + * @param uri + * @return + * @throws IOException + * @throws IllegalArgumentException + * @throws URISyntaxException + */ + public static URL toURL(URI uri) throws IOException, IllegalArgumentException, URISyntaxException { + final URL url; + final String uriSchema = uri.getScheme(); + final boolean isJAR = IOUtil.JAR_SCHEME.equals(uriSchema); + final URI specificURI = isJAR ? JarUtil.getJarSubURI(uri) : uri; + if( IOUtil.FILE_SCHEME.equals( specificURI.getScheme() ) ) { + final File f = new File(specificURI); + if( specificURI == uri ) { + url = new URL(IOUtil.FILE_SCHEME+IOUtil.SCHEME_SEPARATOR+f.getPath()); + // url = f.toURI().toURL(); // Doesn't work, since it uses encoded path! + } else { + final String post = isJAR ? IOUtil.JAR_SCHEME_SEPARATOR + JarUtil.getJarEntry(uri) : ""; + final String urlS = uriSchema+IOUtil.SCHEME_SEPARATOR+IOUtil.FILE_SCHEME+IOUtil.SCHEME_SEPARATOR+f.getPath()+post; + url = new URL(urlS); + } + } else { + url = uri.toURL(); + } + return url; + } + /*** * * RESOURCE LOCATION STUFF diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java index 4045cfa..9ea6f70 100644 --- a/src/java/com/jogamp/common/util/JarUtil.java +++ b/src/java/com/jogamp/common/util/JarUtil.java @@ -142,10 +142,10 @@ public class JarUtil { final URL url = IOUtil.getClassURL(clazzBinName, cl); final String scheme = url.getProtocol(); if( null != resolver && - !scheme.startsWith( IOUtil.JAR_SCHEME ) && - !scheme.startsWith( IOUtil.FILE_SCHEME ) && - !scheme.startsWith( IOUtil.HTTP_SCHEME ) && - !scheme.startsWith( IOUtil.HTTPS_SCHEME ) ) + !scheme.equals( IOUtil.JAR_SCHEME ) && + !scheme.equals( IOUtil.FILE_SCHEME ) && + !scheme.equals( IOUtil.HTTP_SCHEME ) && + !scheme.equals( IOUtil.HTTPS_SCHEME ) ) { final URL _url = resolver.resolve( url ); uri = _url.toURI(); @@ -252,7 +252,6 @@ public class JarUtil { * * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()}, * i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code> - * @param cl * @return <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code> * @throws IllegalArgumentException if the URI doesn't match the expected formatting or is null * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI @@ -286,6 +285,36 @@ public class JarUtil { } return new URI(uriS); } + + /** + * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code> + * Jar file's entry <code>/com/jogamp/common/GlueGenVersion.class</code> will be returned. + * + * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()}, + * i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code> + * @return <code>/com/jogamp/common/GlueGenVersion.class</code> + * @see {@link IOUtil#getClassURL(String, ClassLoader)} + */ + public static String getJarEntry(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+">"); + } + String uriS = classJarURI.getRawSchemeSpecificPart(); + + // from + // file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class + // to + // file:/some/path/gluegen-rt.jar + int idx = uriS.lastIndexOf('!'); + if (0 <= idx) { + return uriS.substring(idx+1); // right of '!' + } else { + throw new IllegalArgumentException("JAR URI does not contain jar uri terminator '!', uri <"+classJarURI+">"); + } + } /** * The Class's <code>com.jogamp.common.GlueGenVersion</code> @@ -335,46 +364,6 @@ public class JarUtil { } /** - * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code> - * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned. - * <p> - * <i>protocol</i> may be "file", "http", etc.. - * </p> - * - * @param aURI "<i>protocol</i>:/some/path/gluegen-rt.jar" - * @return "<i>protocol</i>:/some/path/" - * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null - * @throws URISyntaxException - */ - public static URI getURIDirname(URI aURI) throws IllegalArgumentException, URISyntaxException { - if(null == aURI) { - throw new IllegalArgumentException("URI is null"); - } - String uriS = aURI.toString(); - if(DEBUG) { - System.out.println("getURIDirname "+aURI+", extForm: "+uriS); - } - // 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 <"+aURI+">"); - } - } - uriS = uriS.substring(0, idx+1); // exclude jar name, include terminal '/' or ':' - - if(DEBUG) { - System.out.println("getJarURIDirname res: "+uriS); - } - return new URI(uriS); - } - - /** * @param baseUri file:/some/path/ * @param jarFileName gluegen-rt.jar * @return jar:file:/some/path/gluegen-rt.jar!/ @@ -433,15 +422,17 @@ public class JarUtil { * @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(URI jarFileURI) throws IOException, IllegalArgumentException { + public static JarFile getJarFile(URI jarFileURI) throws IOException, IllegalArgumentException, URISyntaxException { if(null == jarFileURI) { throw new IllegalArgumentException("null jarFileURI"); } if(DEBUG) { - System.out.println("getJarFile: "+jarFileURI); + System.out.println("getJarFile: "+jarFileURI.toString()); } - final URL jarFileURL = jarFileURI.toURL(); + final URL jarFileURL = IOUtil.toURL(jarFileURI); + // final URL jarFileURL = jarFileURI.toURL(); // doesn't work due to encoded path even w/ file schema! final URLConnection urlc = jarFileURL.openConnection(); if(urlc instanceof JarURLConnection) { JarURLConnection jarConnection = (JarURLConnection)jarFileURL.openConnection(); diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java index b17dd52..4c505f9 100644 --- a/src/java/com/jogamp/common/util/cache/TempJarCache.java +++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java @@ -206,8 +206,10 @@ public class TempJarCache { * @param jarURI * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed * @throws SecurityException + * @throws URISyntaxException + * @throws IllegalArgumentException */ - public synchronized static final void addNativeLibs(Class<?> certClass, URI jarURI) throws IOException, SecurityException { + public synchronized static final void addNativeLibs(Class<?> certClass, URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { final LoadState nativeLibJarsLS = nativeLibJars.get(jarURI); if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ) { nativeLibJars.put(jarURI, LoadState.LOOKED_UP); @@ -233,8 +235,10 @@ public class TempJarCache { * @param jarURI * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed * @throws SecurityException + * @throws URISyntaxException + * @throws IllegalArgumentException */ - public synchronized static final void addClasses(Class<?> certClass, URI jarURI) throws IOException, SecurityException { + public synchronized static final void addClasses(Class<?> certClass, URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { final LoadState classFileJarsLS = classFileJars.get(jarURI); if( !testLoadState(classFileJarsLS, LoadState.LOOKED_UP) ) { classFileJars.put(jarURI, LoadState.LOOKED_UP); @@ -259,8 +263,10 @@ public class TempJarCache { * @return * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed * @throws SecurityException + * @throws URISyntaxException + * @throws IllegalArgumentException */ - public synchronized static final void addResources(Class<?> certClass, URI jarURI) throws IOException, SecurityException { + public synchronized static final void addResources(Class<?> certClass, URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { final LoadState resourceFileJarsLS = resourceFileJars.get(jarURI); if( !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) { resourceFileJars.put(jarURI, LoadState.LOOKED_UP); @@ -288,8 +294,10 @@ public class TempJarCache { * @param jarURI * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed * @throws SecurityException + * @throws URISyntaxException + * @throws IllegalArgumentException */ - public synchronized static final void addAll(Class<?> certClass, URI jarURI) throws IOException, SecurityException { + public synchronized static final void addAll(Class<?> certClass, URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { checkInitialized(); if(null == jarURI) { throw new IllegalArgumentException("jarURI is null"); @@ -400,9 +408,11 @@ public class TempJarCache { * * @throws IOException * @throws SecurityException + * @throws URISyntaxException + * @throws IllegalArgumentException */ public synchronized static final void bootstrapNativeLib(Class<?> certClass, String libBaseName, URI jarURI) - throws IOException, SecurityException { + throws IOException, SecurityException, IllegalArgumentException, URISyntaxException { checkInitialized(); boolean ok = false; int countEntries = 0; |