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);
224 System.err.println(
"getJarName res: "+ssp);
245 public static Uri.Encoded
getJarBasename(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
259 if(
null == classJarUri) {
260 throw new IllegalArgumentException(
"Uri is null");
263 throw new IllegalArgumentException(
"Uri is not a using scheme "+
Uri.
JAR_SCHEME+
": <"+classJarUri+
">");
273 final Uri.Encoded res = uriSSP.substring(idx+1);
276 System.err.println(
"getJarEntry res: "+classJarUri+
" -> "+uriSSP+
" -> "+idx+
" -> "+res);
280 throw new IllegalArgumentException(
"JAR Uri does not contain jar uri terminator '!', uri <"+classJarUri+
">");
300 public static Uri getJarFileUri(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
301 if(
null == clazzBinName ||
null == cl) {
302 throw new IllegalArgumentException(
"null arguments: clazzBinName "+clazzBinName+
", cl "+cl);
307 System.err.println(
"getJarFileUri res: "+uri);
320 if(
null == baseUri ||
null == jarFileName) {
321 throw new IllegalArgumentException(
"null arguments: baseUri "+baseUri+
", jarFileName "+jarFileName);
332 public static Uri getJarFileUri(
final Uri jarSubUri)
throws IllegalArgumentException, URISyntaxException {
333 if(
null == jarSubUri) {
334 throw new IllegalArgumentException(
"jarSubUri is null");
346 if(
null == jarSubUriS) {
347 throw new IllegalArgumentException(
"jarSubUriS is null");
360 if(
null == jarEntry) {
361 throw new IllegalArgumentException(
"jarEntry is null");
363 return Uri.
cast(jarFileUri.toString()+jarEntry);
375 public static JarFile
getJarFile(
final String clazzBinName,
final ClassLoader cl)
throws IOException, IllegalArgumentException, URISyntaxException {
386 public static JarFile
getJarFile(
final Uri jarFileUri)
throws IOException, IllegalArgumentException, URISyntaxException {
387 if(
null == jarFileUri) {
388 throw new IllegalArgumentException(
"null jarFileUri");
391 System.err.println(
"getJarFile.0: "+jarFileUri.toString());
393 final URL jarFileURL = jarFileUri.toURL();
395 System.err.println(
"getJarFile.1: "+jarFileURL.toString());
397 final URLConnection urlc = jarFileURL.openConnection();
398 if(urlc instanceof JarURLConnection) {
399 final JarURLConnection jarConnection = (JarURLConnection)jarFileURL.openConnection();
400 final JarFile jarFile = jarConnection.getJarFile();
402 System.err.println(
"getJarFile res: "+jarFile.getName());
407 System.err.println(
"getJarFile res: NULL");
456 public static Uri getRelativeOf(
final Class<?> classFromJavaJar,
final Uri.
Encoded cutOffInclSubDir,
final Uri.
Encoded relResPath)
throws IllegalArgumentException, IOException, URISyntaxException {
457 final ClassLoader cl = classFromJavaJar.getClassLoader();
460 System.err.println(
"JarUtil.getRelativeOf: "+
"(classFromJavaJar "+classFromJavaJar+
", classJarUri "+classJarUri+
461 ", cutOffInclSubDir "+cutOffInclSubDir+
", relResPath "+relResPath+
"): ");
464 if(
null == jarSubUri) {
465 throw new IllegalArgumentException(
"JarSubUri is null of: "+classJarUri);
469 System.err.println(
"JarUtil.getRelativeOf: "+
"uri "+jarSubUri.
toString()+
" -> "+jarUriRoot);
471 final Uri.Encoded resUri;
472 if(
null == cutOffInclSubDir || jarUriRoot.endsWith(cutOffInclSubDir.get()) ) {
473 resUri = jarUriRoot.
concat(relResPath);
475 resUri = jarUriRoot.
concat(cutOffInclSubDir).
concat(relResPath);
478 System.err.println(
"JarUtil.getRelativeOf: "+
"... -> "+resUri);
482 System.err.println(
"JarUtil.getRelativeOf: "+
"fin "+resJarUri);
492 System.err.println(
"JarUtil: getNativeLibNames: "+jarFile);
495 final Map<String,String> nameMap =
new HashMap<String, String>();
496 final Enumeration<JarEntry> entries = jarFile.entries();
498 while (entries.hasMoreElements()) {
499 final JarEntry entry = entries.nextElement();
500 final String entryName = entry.getName();
503 if(
null != baseName) {
504 nameMap.put(baseName, entryName);
546 public static final int extract(
final File dest,
final Map<String, String> nativeLibMap,
547 final JarFile jarFile,
548 final String nativeLibraryPath,
549 final boolean extractNativeLibraries,
550 final boolean extractClassFiles,
final boolean extractOtherFiles)
throws IOException {
553 System.err.println(
"JarUtil: extract: "+jarFile.getName()+
" -> "+dest+
554 ", extractNativeLibraries "+extractNativeLibraries+
" ("+nativeLibraryPath+
")"+
555 ", extractClassFiles "+extractClassFiles+
556 ", extractOtherFiles "+extractOtherFiles);
560 final Enumeration<JarEntry> entries = jarFile.entries();
561 while (entries.hasMoreElements()) {
562 final JarEntry entry = entries.nextElement();
563 final String entryName = entry.getName();
567 final boolean isNativeLib =
null != libBaseName;
569 if(!extractNativeLibraries) {
571 System.err.println(
"JarUtil: JarEntry : " + entryName +
" native-lib skipped, skip all native libs");
575 if(
null != nativeLibraryPath) {
576 final String nativeLibraryPathS;
577 final String dirnameS;
579 nativeLibraryPathS =
IOUtil.
slashify(nativeLibraryPath,
false ,
true );
581 }
catch (
final URISyntaxException e) {
582 throw new IOException(e);
584 if( !nativeLibraryPathS.equals(dirnameS) ) {
586 System.err.println(
"JarUtil: JarEntry : " + entryName +
" native-lib skipped, not in path: "+nativeLibraryPathS);
593 final boolean isClassFile = entryName.endsWith(
".class");
594 if(isClassFile && !extractClassFiles) {
596 System.err.println(
"JarUtil: JarEntry : " + entryName +
" class-file skipped");
601 if(!isNativeLib && !isClassFile && !extractOtherFiles) {
603 System.err.println(
"JarUtil: JarEntry : " + entryName +
" other-file skipped");
608 final boolean isDir = entryName.endsWith(
"/");
610 final boolean isRootEntry = entryName.indexOf(
'/') == -1 &&
611 entryName.indexOf(File.separatorChar) == -1;
614 System.err.println(
"JarUtil: JarEntry : isNativeLib " + isNativeLib +
615 ", isClassFile " + isClassFile +
", isDir " + isDir +
616 ", isRootEntry " + isRootEntry );
619 final File destFile =
new File(dest, entryName);
622 System.err.println(
"JarUtil: MKDIR: " + entryName +
" -> " + destFile );
626 final File destFolder =
new File(destFile.getParent());
627 if(!destFolder.exists()) {
629 System.err.println(
"JarUtil: MKDIR (parent): " + entryName +
" -> " + destFolder );
633 final InputStream in =
new BufferedInputStream(jarFile.getInputStream(entry));
634 final OutputStream out =
new BufferedOutputStream(
new FileOutputStream(destFile));
642 boolean addedAsNativeLib =
false;
645 if (isNativeLib && ( isRootEntry || !nativeLibMap.containsKey(libBaseName) ) ) {
646 nativeLibMap.put(libBaseName, destFile.getAbsolutePath());
647 addedAsNativeLib =
true;
648 fixNativeLibAttribs(destFile);
652 System.err.println(
"JarUtil: EXTRACT["+num+
"]: [" + libBaseName +
" -> ] " + entryName +
" -> " + destFile +
": "+numBytes+
" bytes, addedAsNativeLib: "+addedAsNativeLib);
665 private final static void fixNativeLibAttribs(
final File file) {
670 final String fileAbsPath = file.getAbsolutePath();
672 fixNativeLibAttribs(fileAbsPath);
674 System.err.println(
"JarUtil.fixNativeLibAttribs: "+fileAbsPath+
" - OK");
676 }
catch (
final Throwable t) {
678 System.err.println(
"JarUtil.fixNativeLibAttribs: "+fileAbsPath+
" - "+t.getClass().getSimpleName()+
": "+t.getMessage());
683 private native
static boolean fixNativeLibAttribs(String fname);
694 throws IOException, SecurityException {
697 System.err.println(
"JarUtil: validateCertificates: "+jarFile.getName());
700 if (rootCerts ==
null || rootCerts.length == 0) {
701 throw new IllegalArgumentException(
"Null certificates passed");
704 final byte[] buf =
new byte[1024];
705 final Enumeration<JarEntry> entries = jarFile.entries();
706 while (entries.hasMoreElements()) {
707 final JarEntry entry = entries.nextElement();
708 if( ! entry.isDirectory() && ! entry.getName().startsWith(
"META-INF/") ) {
710 validateCertificate(rootCerts, jarFile, entry, buf);
719 private static final void validateCertificate(
final Certificate[] rootCerts,
720 final JarFile jar,
final JarEntry entry,
final byte[] buf)
throws IOException, SecurityException {
723 System.err.println(
"JarUtil: validate JarEntry : " + entry.getName());
729 final InputStream is = jar.getInputStream(entry);
731 while (is.read(buf) > 0) { }
737 final Certificate[] nativeCerts = entry.getCertificates();
738 if (nativeCerts ==
null || nativeCerts.length == 0) {
739 throw new SecurityException(
"no certificate for " + entry.getName() +
" in " + jar.getName());
742 if( !SecurityUtil.equals(rootCerts, nativeCerts) ) {
743 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...