28package com.jogamp.common.util;
30import java.io.BufferedInputStream;
31import java.io.BufferedOutputStream;
33import java.io.FileOutputStream;
34import java.io.IOException;
35import java.io.InputStream;
36import java.io.OutputStream;
37import java.net.JarURLConnection;
38import java.net.URISyntaxException;
40import java.net.URLConnection;
41import java.security.cert.Certificate;
42import java.util.Enumeration;
43import java.util.HashMap;
45import java.util.jar.JarEntry;
46import java.util.jar.JarFile;
48import com.jogamp.common.net.Uri;
49import com.jogamp.common.os.NativeLibrary;
50import com.jogamp.common.os.Platform;
52import jogamp.common.Debug;
55 private static final boolean DEBUG = Debug.debug(
"JarUtil");
57 private static final int BUFFER_SIZE = 4096;
86 public static void setResolver(
final Resolver r)
throws IllegalArgumentException, IllegalStateException, SecurityException {
88 throw new IllegalArgumentException(
"Null Resolver passed");
91 if(resolver !=
null) {
92 throw new IllegalStateException(
"Resolver already set!");
95 final SecurityManager security = System.getSecurityManager();
96 if(security !=
null) {
97 security.checkSetFactory();
116 public static boolean hasJarUri(
final String clazzBinName,
final ClassLoader cl) {
118 return null !=
getJarUri(clazzBinName, cl);
119 }
catch (
final Exception e) { }
139 public static Uri getJarUri(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
140 if(
null == clazzBinName ||
null == cl) {
141 throw new IllegalArgumentException(
"null arguments: clazzBinName "+clazzBinName+
", cl "+cl);
147 final String scheme = url.getProtocol();
148 if(
null != resolver &&
154 final URL _url = resolver.
resolve( url );
157 System.err.println(
"getJarUri Resolver: "+url+
"\n\t-> "+_url+
"\n\t-> "+uri);
162 System.err.println(
"getJarUri Default "+url+
"\n\t-> "+uri);
167 throw new IllegalArgumentException(
"Uri is not using scheme "+
Uri.
JAR_SCHEME+
": <"+uri+
">");
170 System.err.println(
"getJarUri res: "+clazzBinName+
" -> "+url+
" -> "+uri);
189 public static Uri.Encoded
getJarBasename(
final Uri classJarUri)
throws IllegalArgumentException {
190 if(
null == classJarUri) {
191 throw new IllegalArgumentException(
"Uri is null");
193 if( !classJarUri.isJarScheme() ) {
194 throw new IllegalArgumentException(
"Uri is not using scheme "+
Uri.
JAR_SCHEME+
": <"+classJarUri+
">");
196 Uri.Encoded ssp = classJarUri.schemeSpecificPart;
204 ssp = ssp.substring(0, idx);
206 throw new IllegalArgumentException(
"Uri does not contain jar uri terminator '!', in <"+classJarUri+
">");
213 idx = ssp.lastIndexOf(
'/');
216 idx = ssp.lastIndexOf(
':');
218 throw new IllegalArgumentException(
"Uri does not contain protocol terminator ':', in <"+classJarUri+
">");
221 ssp = ssp.substring(idx+1);
223 if(0 >= ssp.lastIndexOf(
".jar")) {
224 throw new IllegalArgumentException(
"No Jar name in <"+classJarUri+
">");
227 System.err.println(
"getJarName res: "+ssp);
248 public static Uri.Encoded
getJarBasename(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
262 if(
null == classJarUri) {
263 throw new IllegalArgumentException(
"Uri is null");
266 throw new IllegalArgumentException(
"Uri is not a using scheme "+
Uri.
JAR_SCHEME+
": <"+classJarUri+
">");
276 final Uri.Encoded res = uriSSP.substring(idx+1);
279 System.err.println(
"getJarEntry res: "+classJarUri+
" -> "+uriSSP+
" -> "+idx+
" -> "+res);
283 throw new IllegalArgumentException(
"JAR Uri does not contain jar uri terminator '!', uri <"+classJarUri+
">");
303 public static Uri getJarFileUri(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
304 if(
null == clazzBinName ||
null == cl) {
305 throw new IllegalArgumentException(
"null arguments: clazzBinName "+clazzBinName+
", cl "+cl);
310 System.err.println(
"getJarFileUri res: "+uri);
323 if(
null == baseUri ||
null == jarFileName) {
324 throw new IllegalArgumentException(
"null arguments: baseUri "+baseUri+
", jarFileName "+jarFileName);
335 public static Uri getJarFileUri(
final Uri jarSubUri)
throws IllegalArgumentException, URISyntaxException {
336 if(
null == jarSubUri) {
337 throw new IllegalArgumentException(
"jarSubUri is null");
349 if(
null == jarSubUriS) {
350 throw new IllegalArgumentException(
"jarSubUriS is null");
363 if(
null == jarEntry) {
364 throw new IllegalArgumentException(
"jarEntry is null");
366 return Uri.
cast(jarFileUri.toString()+jarEntry);
378 public static JarFile
getJarFile(
final String clazzBinName,
final ClassLoader cl)
throws IOException, IllegalArgumentException, URISyntaxException {
389 public static JarFile
getJarFile(
final Uri jarFileUri)
throws IOException, IllegalArgumentException, URISyntaxException {
390 if(
null == jarFileUri) {
391 throw new IllegalArgumentException(
"null jarFileUri");
394 System.err.println(
"getJarFile.0: "+jarFileUri.toString());
396 final URL jarFileURL = jarFileUri.toURL();
398 System.err.println(
"getJarFile.1: "+jarFileURL.toString());
400 final URLConnection urlc = jarFileURL.openConnection();
401 if(urlc instanceof JarURLConnection) {
402 final JarURLConnection jarConnection = (JarURLConnection)jarFileURL.openConnection();
403 final JarFile jarFile = jarConnection.getJarFile();
405 System.err.println(
"getJarFile res: "+jarFile.getName());
410 System.err.println(
"getJarFile res: NULL");
459 public static Uri getRelativeOf(
final Class<?> classFromJavaJar,
final Uri.
Encoded cutOffInclSubDir,
final Uri.
Encoded relResPath)
throws IllegalArgumentException, IOException, URISyntaxException {
460 final ClassLoader cl = classFromJavaJar.getClassLoader();
463 System.err.println(
"JarUtil.getRelativeOf: "+
"(classFromJavaJar "+classFromJavaJar+
", classJarUri "+classJarUri+
464 ", cutOffInclSubDir "+cutOffInclSubDir+
", relResPath "+relResPath+
"): ");
467 if(
null == jarSubUri) {
468 throw new IllegalArgumentException(
"JarSubUri is null of: "+classJarUri);
472 System.err.println(
"JarUtil.getRelativeOf: "+
"uri "+jarSubUri.
toString()+
" -> "+jarUriRoot);
474 final Uri.Encoded resUri;
475 if(
null == cutOffInclSubDir || jarUriRoot.endsWith(cutOffInclSubDir.get()) ) {
476 resUri = jarUriRoot.
concat(relResPath);
478 resUri = jarUriRoot.
concat(cutOffInclSubDir).
concat(relResPath);
481 System.err.println(
"JarUtil.getRelativeOf: "+
"... -> "+resUri);
485 System.err.println(
"JarUtil.getRelativeOf: "+
"fin "+resJarUri);
495 System.err.println(
"JarUtil: getNativeLibNames: "+jarFile);
498 final Map<String,String> nameMap =
new HashMap<String, String>();
499 final Enumeration<JarEntry> entries = jarFile.entries();
501 while (entries.hasMoreElements()) {
502 final JarEntry entry = entries.nextElement();
503 final String entryName = entry.getName();
506 if(
null != baseName) {
507 nameMap.put(baseName, entryName);
549 public static final int extract(
final File dest,
final Map<String, String> nativeLibMap,
550 final JarFile jarFile,
551 final String nativeLibraryPath,
552 final boolean extractNativeLibraries,
553 final boolean extractClassFiles,
final boolean extractOtherFiles)
throws IOException {
556 System.err.println(
"JarUtil: extract: "+jarFile.getName()+
" -> "+dest+
557 ", extractNativeLibraries "+extractNativeLibraries+
" ("+nativeLibraryPath+
")"+
558 ", extractClassFiles "+extractClassFiles+
559 ", extractOtherFiles "+extractOtherFiles);
563 final Enumeration<JarEntry> entries = jarFile.entries();
564 while (entries.hasMoreElements()) {
565 final JarEntry entry = entries.nextElement();
566 final String entryName = entry.getName();
570 final boolean isNativeLib =
null != libBaseName;
572 if(!extractNativeLibraries) {
574 System.err.println(
"JarUtil: JarEntry : " + entryName +
" native-lib skipped, skip all native libs");
578 if(
null != nativeLibraryPath) {
579 final String nativeLibraryPathS;
580 final String dirnameS;
582 nativeLibraryPathS =
IOUtil.
slashify(nativeLibraryPath,
false ,
true );
584 }
catch (
final URISyntaxException e) {
585 throw new IOException(e);
587 if( !nativeLibraryPathS.equals(dirnameS) ) {
589 System.err.println(
"JarUtil: JarEntry : " + entryName +
" native-lib skipped, not in path: "+nativeLibraryPathS);
596 final boolean isClassFile = entryName.endsWith(
".class");
597 if(isClassFile && !extractClassFiles) {
599 System.err.println(
"JarUtil: JarEntry : " + entryName +
" class-file skipped");
604 if(!isNativeLib && !isClassFile && !extractOtherFiles) {
606 System.err.println(
"JarUtil: JarEntry : " + entryName +
" other-file skipped");
611 final boolean isDir = entryName.endsWith(
"/");
613 final boolean isRootEntry = entryName.indexOf(
'/') == -1 &&
614 entryName.indexOf(File.separatorChar) == -1;
617 System.err.println(
"JarUtil: JarEntry : isNativeLib " + isNativeLib +
618 ", isClassFile " + isClassFile +
", isDir " + isDir +
619 ", isRootEntry " + isRootEntry );
622 final File destFile =
new File(dest, entryName);
625 System.err.println(
"JarUtil: MKDIR: " + entryName +
" -> " + destFile );
629 final File destFolder =
new File(destFile.getParent());
630 if(!destFolder.exists()) {
632 System.err.println(
"JarUtil: MKDIR (parent): " + entryName +
" -> " + destFolder );
636 final InputStream in =
new BufferedInputStream(jarFile.getInputStream(entry));
637 final OutputStream out =
new BufferedOutputStream(
new FileOutputStream(destFile));
645 boolean addedAsNativeLib =
false;
648 if (isNativeLib && ( isRootEntry || !nativeLibMap.containsKey(libBaseName) ) ) {
649 nativeLibMap.put(libBaseName, destFile.getAbsolutePath());
650 addedAsNativeLib =
true;
651 fixNativeLibAttribs(destFile);
655 System.err.println(
"JarUtil: EXTRACT["+num+
"]: [" + libBaseName +
" -> ] " + entryName +
" -> " + destFile +
": "+numBytes+
" bytes, addedAsNativeLib: "+addedAsNativeLib);
668 private final static void fixNativeLibAttribs(
final File file) {
673 final String fileAbsPath = file.getAbsolutePath();
675 fixNativeLibAttribs(fileAbsPath);
677 System.err.println(
"JarUtil.fixNativeLibAttribs: "+fileAbsPath+
" - OK");
679 }
catch (
final Throwable t) {
681 System.err.println(
"JarUtil.fixNativeLibAttribs: "+fileAbsPath+
" - "+t.getClass().getSimpleName()+
": "+t.getMessage());
686 private native
static boolean fixNativeLibAttribs(String fname);
697 throws IOException, SecurityException {
700 System.err.println(
"JarUtil: validateCertificates: "+jarFile.getName());
703 if (rootCerts ==
null || rootCerts.length == 0) {
704 throw new IllegalArgumentException(
"Null certificates passed");
707 final byte[] buf =
new byte[1024];
708 final Enumeration<JarEntry> entries = jarFile.entries();
709 while (entries.hasMoreElements()) {
710 final JarEntry entry = entries.nextElement();
711 if( ! entry.isDirectory() && ! entry.getName().startsWith(
"META-INF/") ) {
713 validateCertificate(rootCerts, jarFile, entry, buf);
722 private static final void validateCertificate(
final Certificate[] rootCerts,
723 final JarFile jar,
final JarEntry entry,
final byte[] buf)
throws IOException, SecurityException {
726 System.err.println(
"JarUtil: validate JarEntry : " + entry.getName());
732 final InputStream is = jar.getInputStream(entry);
734 while (is.read(buf) > 0) { }
740 final Certificate[] nativeCerts = entry.getCertificates();
741 if (nativeCerts ==
null || nativeCerts.length == 0) {
742 throw new SecurityException(
"no certificate for " + entry.getName() +
" in " + jar.getName());
745 if( !SecurityUtil.equals(rootCerts, nativeCerts) ) {
746 throw new SecurityException(
"certificates not equal for " + entry.getName() +
" in " + jar.getName());
Immutable RFC3986 encoded string.
final int lastIndexOf(final int ch)
See String#lastIndexOf(int).
Encoded concat(final Encoded encoded)
See String#concat(String).
This class implements an immutable Uri as defined by RFC 2396.
final Encoded schemeSpecificPart
Encoded scheme-specific-part, never null.
static final String HTTP_SCHEME
{@value}
static Uri valueOf(final File file)
Creates a new Uri instance using the given File instance.
static final char JAR_SCHEME_SEPARATOR
A JAR sub-protocol is separated from the JAR entry w/ this separator {@value}.
final String toString()
Returns the encoded input as String, never null, same as getEncoded().
final Uri getContainedUri()
If this instance's schemeSpecificPart contains a Uri itself, a sub-Uri, return schemeSpecificPart + #...
static final String HTTPS_SCHEME
{@value}
static final String FILE_SCHEME
{@value}
static final String JAR_SCHEME
{@value}
static final char SCHEME_SEPARATOR
{@value}
final boolean isJarScheme()
Returns true, if this instance is a jar scheme, otherwise false.
Uri getDirectory()
Returns this Uri's directory Uri.
static Uri cast(final String encodedUri)
Casts the given encoded String to a new Encoded instance used to create the resulting Uri instance vi...
final Encoded getEncoded()
Returns the encoded input, never null.
Provides low-level, relatively platform-independent access to shared ("native") libraries.
static final String isValidNativeLibraryName(final String libName, final boolean isLowerCaseAlready)
Comparison of prefix and suffix of the given libName's basename is performed case insensitive
static URL getClassURL(final String clazzBinName, final ClassLoader cl)
static int copyStream2Stream(final InputStream in, final OutputStream out)
Copy the complete specified input stream to the specified output stream.
static String slashify(final String path, final boolean startWithSlash, final boolean endWithSlash)
static String getDirname(String fname)
Returns unified '/' dirname including the last '/'.
static final int extract(final File dest, final Map< String, String > nativeLibMap, final JarFile jarFile, final String nativeLibraryPath, final boolean extractNativeLibraries, final boolean extractClassFiles, final boolean extractOtherFiles)
Extract the files of the given jar file.
static Uri getJarEntryUri(final Uri jarFileUri, final Uri.Encoded jarEntry)
static Uri getJarUri(final String clazzBinName, final ClassLoader cl)
The Class's "com.jogamp.common.GlueGenVersion" Uri jar:sub_protocol:/some/path/gluegen-rt....
static boolean hasJarUri(final String clazzBinName, final ClassLoader cl)
Returns true if the Class's "com.jogamp.common.GlueGenVersion" is loaded from a JarFile and hence has...
static Uri.Encoded getJarBasename(final String clazzBinName, final ClassLoader cl)
The Class's com.jogamp.common.GlueGenVersion Uri jar:sub_protocol:/some/path/gluegen-rt....
static Uri.Encoded getJarBasename(final Uri classJarUri)
The Class's Jar Uri jar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion....
static Uri getJarFileUri(final Uri.Encoded jarSubUriS)
static Map< String, String > getNativeLibNames(final JarFile jarFile)
Return a map from native-lib-base-name to entry-name.
static Uri.Encoded getJarEntry(final Uri classJarUri)
The Class's Jar Uri jar:sub_protocol:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion....
static Uri getJarFileUri(final String clazzBinName, final ClassLoader cl)
The Class's "com.jogamp.common.GlueGenVersion" Uri jar:sub_protocol:/some/path/gluegen-rt....
static Uri getJarFileUri(final Uri jarSubUri)
static final void validateCertificates(final Certificate[] rootCerts, final JarFile jarFile)
Validate the certificates for each native Lib in the jar file.
static Uri getJarFileUri(final Uri baseUri, final Uri.Encoded jarFileName)
static JarFile getJarFile(final String clazzBinName, final ClassLoader cl)
static JarFile getJarFile(final Uri jarFileUri)
static Uri getRelativeOf(final Class<?> classFromJavaJar, final Uri.Encoded cutOffInclSubDir, final Uri.Encoded relResPath)
Locates the Jar file Uri of a given resource relative to a given class's Jar's Uri.
static void setResolver(final Resolver r)
Setting a custom Resolver instance.
Interface allowing users to provide an URL resolver that will convert custom classloader URLs like Ec...