GlueGen: src/java/com/jogamp/common/util/IOUtil.java Source File

GlueGen v2.6.0-rc-20250822 GlueGen, Native Binding Generator for Java™ (public API).

IOUtil.java
Go to the documentation of this file.
1/**
2 * Copyright 2010 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.common.util;
30
31import java.io.BufferedInputStream;
32import java.io.BufferedOutputStream;
33import java.io.Closeable;
34import java.io.File;
35import java.io.FileOutputStream;
36import java.io.FilePermission;
37import java.io.FileWriter;
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.OutputStream;
41import java.io.PrintStream;
42import java.io.Reader;
43import java.io.SyncFailedException;
44import java.lang.ref.WeakReference;
45import java.lang.reflect.Constructor;
46import java.lang.reflect.Method;
47import java.net.URISyntaxException;
48import java.net.URL;
49import java.net.URLConnection;
50import java.nio.ByteBuffer;
51import java.security.PrivilegedAction;
52import java.util.ArrayList;
53import java.util.List;
54import java.util.Locale;
55import java.util.regex.Pattern;
56
57import jogamp.common.Debug;
58import jogamp.common.os.AndroidUtils;
59import jogamp.common.os.PlatformPropsImpl;
60
61import com.jogamp.common.ExceptionUtils;
62import com.jogamp.common.JogampRuntimeException;
63import com.jogamp.common.net.AssetURLContext;
64import com.jogamp.common.net.Uri;
65import com.jogamp.common.nio.Buffers;
66import com.jogamp.common.os.MachineDataInfo;
67import com.jogamp.common.os.Platform;
68
69 public class IOUtil {
70 public static final boolean DEBUG;
71 private static final boolean DEBUG_EXE;
72 private static final boolean DEBUG_EXE_NOSTREAM;
73 private static final boolean DEBUG_EXE_EXISTING_FILE;
74 private static final boolean testTempDirExec;
75 private static final Method fileToPathGetter;
76 private static final Method isExecutableQuery;
77 private static final boolean useNativeExeFile;
78
79 static {
80 final boolean _props[] = { false, false, false, false, false, false };
81 final Method[] res = SecurityUtil.doPrivileged(new PrivilegedAction<Method[]>() {
82 @Override
83 public Method[] run() {
84 final Method[] res = new Method[] { null, null };
85 try {
86 int i=0;
87 _props[i++] = Debug.debug("IOUtil");
88 _props[i++] = PropertyAccess.isPropertyDefined("jogamp.debug.IOUtil.Exe", true);
89 _props[i++] = PropertyAccess.isPropertyDefined("jogamp.debug.IOUtil.Exe.NoStream", true);
90 // For security reasons, we have to hardcode this, i.e. disable this manual debug feature!
91 _props[i++] = false; // PropertyAccess.isPropertyDefined("jogamp.debug.IOUtil.Exe.ExistingFile", true);
92 _props[i++] = PropertyAccess.getBooleanProperty("jogamp.gluegen.TestTempDirExec", true, true);
93 _props[i++] = PropertyAccess.getBooleanProperty("jogamp.gluegen.UseNativeExeFile", true, false);
94
95 // Java 1.7
96 i=0;
97 res[i] = File.class.getDeclaredMethod("toPath");
98 res[i++].setAccessible(true);
99 final Class<?> nioPathClz = ReflectionUtil.getClass("java.nio.file.Path", false, IOUtil.class.getClassLoader());
100 final Class<?> nioFilesClz = ReflectionUtil.getClass("java.nio.file.Files", false, IOUtil.class.getClassLoader());
101 res[i] = nioFilesClz.getDeclaredMethod("isExecutable", nioPathClz);
102 res[i++].setAccessible(true);
103 } catch (final Throwable t) {
104 if(_props[0]) {
105 ExceptionUtils.dumpThrowable("ioutil-init", t);
106 }
107 }
108 return res;
109 }
110 });
111 {
112 int i=0;
113 DEBUG = _props[i++];
114 DEBUG_EXE = _props[i++];
115 DEBUG_EXE_NOSTREAM = _props[i++];
116 DEBUG_EXE_EXISTING_FILE = _props[i++];
117 testTempDirExec = _props[i++];
118 useNativeExeFile = _props[i++];
119
120 i=0;
121 fileToPathGetter = res[i++];
122 isExecutableQuery = res[i++];
123 }
124 }
125
126 /** Std. temporary directory property key <code>java.io.tmpdir</code>. */
127 private static final String java_io_tmpdir_propkey = "java.io.tmpdir";
128 private static final String user_home_propkey = "user.home";
129 private static final String XDG_CACHE_HOME_envkey = "XDG_CACHE_HOME";
130
131 /** Subdirectory within platform's temporary root directory where all JogAmp related temp files are being stored: {@code jogamp} */
132 public static final String tmpSubDir = "jogamp";
133
134 private IOUtil() {}
135
136 /**
137 * Since usage of {@link java.io.FileOutputStream} is considered security critical,
138 * we need to check it's availability for each use.
139 * <p>
140 * In case a SecurityManager is installed, privileged access is required.
141 * </p>
142 *
143 * @return the constructor of {@link java.io.FileOutputStream} if available and
144 * no SecurityManager is installed or privileged access is granted.
145 * Otherwise null.
146 *
147 */
148 private static final Constructor<?> getFOSCtor() {
149 Constructor<?> _fosCtor;
150 Throwable _t;
151 try {
152 _fosCtor = ReflectionUtil.getConstructor("java.io.FileOutputStream", new Class<?>[] { File.class }, true, IOUtil.class.getClassLoader());
153 _t = null;
154 } catch (final Throwable t) {
155 _fosCtor = null;
156 _t = t;
157 }
158 if(DEBUG) {
159 System.err.println("IOUtil: java.io.FileOutputStream available: "+(null != _fosCtor));
160 if(null!=_t) {
161 _t.printStackTrace();
162 }
163 }
164 return _fosCtor;
165 }
166
167 /***
168 *
169 * STREAM COPY STUFF
170 *
171 */
172
173 /**
174 * Copy the complete specified URL resource to the specified output file. The total
175 * number of bytes written is returned.
176 *
177 * @param conn the open URLConnection
178 * @param outFile the destination
179 * @return
180 * @throws IOException
181 */
182 public static int copyURLConn2File(final URLConnection conn, final File outFile) throws IOException {
183 conn.connect(); // redundant
184
185 int totalNumBytes = 0;
186 final InputStream in = new BufferedInputStream(conn.getInputStream());
187 try {
188 totalNumBytes = copyStream2File(in, outFile);
189 } finally {
190 in.close();
191 }
192 return totalNumBytes;
193 }
194
195 /**
196 * Copy the complete specified input stream to the specified output file. The total
197 * number of bytes written is returned.
198 *
199 * @param in the source
200 * @param outFile the destination
201 * @return
202 * @throws IOException
203 */
204 public static int copyStream2File(final InputStream in, final File outFile) throws IOException {
205 final OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
206 try {
207 return copyStream2Stream(in, out);
208 } finally {
209 out.close();
210 }
211 }
212
213 /**
214 * Copy the complete specified input stream to the specified output stream. The total
215 * number of bytes written is returned.
216 *
217 * @param in the source
218 * @param out the destination
219 * @return
220 * @throws IOException
221 */
222 public static int copyStream2Stream(final InputStream in, final OutputStream out) throws IOException {
223 return copyStream2Stream(Platform.getMachineDataInfo().pageSizeInBytes(), in, out);
224 }
225
226 /**
227 * Copy the complete specified input stream to the specified output stream. The total
228 * number of bytes written is returned.
229 *
230 * @param bufferSize the intermediate buffer size, should be {@link MachineDataInfo#pageSizeInBytes()} for best performance.
231 * @param in the source
232 * @param out the destination
233 * @return
234 * @throws IOException
235 */
236 public static int copyStream2Stream(final int bufferSize, final InputStream in, final OutputStream out) throws IOException {
237 final byte[] buf = new byte[bufferSize];
238 int numBytes = 0;
239 while (true) {
240 int count;
241 if ((count = in.read(buf)) == -1) {
242 break;
243 }
244 out.write(buf, 0, count);
245 numBytes += count;
246 }
247 return numBytes;
248 }
249
250 public static StringBuilder appendCharStream(final StringBuilder sb, final Reader r) throws IOException {
251 final char[] cbuf = new char[1024];
252 int count;
253 while( 0 < ( count = r.read(cbuf) ) ) {
254 sb.append(cbuf, 0, count);
255 }
256 return sb;
257 }
258
259 /**
260 * Copy the complete specified input stream to a byte array, which is being returned.
261 */
262 public static byte[] copyStream2ByteArray(InputStream stream) throws IOException {
263 if( !(stream instanceof BufferedInputStream) ) {
264 stream = new BufferedInputStream(stream);
265 }
266 int totalRead = 0;
267 int avail = stream.available();
268 byte[] data = new byte[avail];
269 int numRead = 0;
270 do {
271 if (totalRead + avail > data.length) {
272 final byte[] newData = new byte[totalRead + avail];
273 System.arraycopy(data, 0, newData, 0, totalRead);
274 data = newData;
275 }
276 numRead = stream.read(data, totalRead, avail);
277 if (numRead >= 0) {
278 totalRead += numRead;
279 }
280 avail = stream.available();
281 } while (avail > 0 && numRead >= 0);
282
283 // just in case the announced avail > totalRead
284 if (totalRead != data.length) {
285 final byte[] newData = new byte[totalRead];
286 System.arraycopy(data, 0, newData, 0, totalRead);
287 data = newData;
288 }
289 return data;
290 }
291
292 /**
293 * Copy the complete specified input stream to a NIO ByteBuffer w/ native byte order, which is being returned.
294 *
295 * @param stream input stream, which will be wrapped into a BufferedInputStream, if not already done.
296 */
297 public static ByteBuffer copyStream2ByteBuffer(final InputStream stream) throws IOException {
298 return copyStream2ByteBuffer(stream, -1);
299 }
300
301 /**
302 * Copy the complete specified input stream to a NIO ByteBuffer w/ native byte order, which is being returned.
303 *
304 * @param stream input stream, which will be wrapped into a BufferedInputStream, if not already done.
305 * @param initialCapacity initial buffer capacity in bytes, if &lt; currently available bytes, initial buffer capacity is set to currently available bytes.
306 */
307 public static ByteBuffer copyStream2ByteBuffer(InputStream stream, int initialCapacity) throws IOException {
308 if( !(stream instanceof BufferedInputStream) ) {
309 stream = new BufferedInputStream(stream);
310 }
311 int avail = stream.available();
312 if( initialCapacity < avail ) {
313 initialCapacity = avail;
314 }
315 final MachineDataInfo machine = Platform.getMachineDataInfo();
316 ByteBuffer data = Buffers.newDirectByteBuffer( machine.pageAlignedSize( initialCapacity ) );
317 final byte[] chunk = new byte[machine.pageSizeInBytes()];
318 int chunk2Read = Math.min(machine.pageSizeInBytes(), avail);
319 int numRead = 0;
320 do {
321 if (avail > data.remaining()) {
322 final ByteBuffer newData = Buffers.newDirectByteBuffer(
323 machine.pageAlignedSize(data.position() + avail) );
324 newData.put(data);
325 data = newData;
326 }
327
328 numRead = stream.read(chunk, 0, chunk2Read);
329 if (numRead > 0) {
330 data.put(chunk, 0, numRead);
331 }
332 avail = stream.available();
333 chunk2Read = Math.min(machine.pageSizeInBytes(), avail);
334 } while ( numRead > 0 ); // EOS: -1 == numRead, EOF maybe reached earlier w/ 0 == numRead
335
336 data.flip();
337 return data;
338 }
339
340 /**
341 * Copy the specified input stream chunk to a NIO ByteBuffer w/ native byte order, which is being returned.
342 *
343 * @param stream input stream, which will be wrapped into a BufferedInputStream, if not already done.
344 * @param skipBytes initial bytes to skip from input stream.
345 * @param byteCount bytes to copy starting after skipBytes.
346 */
347 public static ByteBuffer copyStreamChunk2ByteBuffer(InputStream stream, int skipBytes, int byteCount) throws IOException {
348 if( !(stream instanceof BufferedInputStream) ) {
349 stream = new BufferedInputStream(stream);
350 }
351 final MachineDataInfo machine = Platform.getMachineDataInfo();
352 final ByteBuffer data = Buffers.newDirectByteBuffer( machine.pageAlignedSize( byteCount ) );
353 final byte[] chunk = new byte[machine.pageSizeInBytes()];
354 int numRead = 1; // EOS: -1 == numRead, EOF maybe reached earlier w/ 0 == numRead
355 while ( numRead > 0 && skipBytes > 0 ) {
356 final int chunk2Read = Math.min(machine.pageSizeInBytes(), skipBytes);
357 numRead = stream.read(chunk, 0, chunk2Read);
358 skipBytes -= numRead;
359 }
360 while ( numRead > 0 && byteCount > 0 ) {
361 final int chunk2Read = Math.min(machine.pageSizeInBytes(), byteCount);
362 numRead = stream.read(chunk, 0, chunk2Read);
363 if (numRead > 0) {
364 data.put(chunk, 0, numRead);
365 }
366 byteCount -= numRead;
367 }
368
369 data.flip();
370 return data;
371 }
372
373 /***
374 *
375 * RESOURCE / FILE NAME STUFF
376 *
377 */
378
379 private static final Pattern patternSingleBS = Pattern.compile("\\\\{1}");
380
381 /**
382 *
383 * @param path
384 * @param startWithSlash
385 * @param endWithSlash
386 * @return
387 * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
388 */
389 public static String slashify(final String path, final boolean startWithSlash, final boolean endWithSlash) throws URISyntaxException {
390 String p = patternSingleBS.matcher(path).replaceAll("/");
391 if (startWithSlash && !p.startsWith("/")) {
392 p = "/" + p;
393 }
394 if (endWithSlash && !p.endsWith("/")) {
395 p = p + "/";
396 }
397 return cleanPathString(p);
398 }
399
400 /**
401 * Returns the lowercase suffix of the given file name (the text
402 * after the last '.' in the file name). Returns null if the file
403 * name has no suffix. Only operates on the given file name;
404 * performs no I/O operations.
405 *
406 * @param file name of the file
407 * @return lowercase suffix of the file name
408 * @throws NullPointerException if file is null
409 */
410
411 public static String getFileSuffix(final File file) {
412 return getFileSuffix(file.getName());
413 }
414
415 /**
416 * Returns the lowercase suffix of the given file name (the text
417 * after the last '.' in the file name). Returns null if the file
418 * name has no suffix. Only operates on the given file name;
419 * performs no I/O operations.
420 *
421 * @param filename name of the file
422 * @return lowercase suffix of the file name
423 * @throws NullPointerException if filename is null
424 */
425 public static String getFileSuffix(final String filename) {
426 final int lastDot = filename.lastIndexOf('.');
427 if (lastDot < 0) {
428 return null;
429 }
430 return toLowerCase(filename.substring(lastDot + 1));
431 }
432 private static String toLowerCase(final String arg) {
433 if (arg == null) {
434 return null;
435 }
436
437 return arg.toLowerCase();
438 }
439
440 /***
441 * @param file
442 * @param allowOverwrite
443 * @return outputStream The resulting output stream
444 * @throws IOException if the file already exists and <code>allowOverwrite</code> is false,
445 * the class {@link java.io.FileOutputStream} is not accessible or
446 * the user does not have sufficient rights to access the local filesystem.
447 */
448 public static FileOutputStream getFileOutputStream(final File file, final boolean allowOverwrite) throws IOException {
449 final Constructor<?> fosCtor = getFOSCtor();
450 if(null == fosCtor) {
451 throw new IOException("Cannot open file (" + file + ") for writing, FileOutputStream feature not available.");
452 }
453 if (file.exists() && !allowOverwrite) {
454 throw new IOException("File already exists (" + file + ") and overwrite=false");
455 }
456 try {
457 return (FileOutputStream) fosCtor.newInstance(new Object[] { file });
458 } catch (final Exception e) {
459 throw new IOException("error opening " + file + " for write. ", e);
460 }
461 }
462
463 public static String getClassFileName(final String clazzBinName) {
464 // or return clazzBinName.replace('.', File.separatorChar) + ".class"; ?
465 return clazzBinName.replace('.', '/') + ".class";
466 }
467
468 /**
469 * @param clazzBinName com.jogamp.common.util.cache.TempJarCache
470 * @param cl ClassLoader to locate the JarFile
471 * @return jar:file:/usr/local/projects/JOGL/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/util/cache/TempJarCache.class
472 * @throws IOException if the jar file could not been found by the ClassLoader
473 */
474 public static URL getClassURL(final String clazzBinName, final ClassLoader cl) throws IOException {
475 final URL url = cl.getResource(getClassFileName(clazzBinName));
476 if(null == url) {
477 throw new IOException("Cannot not find: "+clazzBinName);
478 }
479 return url;
480 }
481
482 /**
483 * Returns the basename of the given fname w/o directory part
484 * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
485 */
486 public static String getBasename(String fname) throws URISyntaxException {
487 fname = slashify(fname, false /* startWithSlash */, false /* endWithSlash */);
488 final int lios = fname.lastIndexOf('/'); // strip off dirname
489 if(lios>=0) {
490 fname = fname.substring(lios+1);
491 }
492 return fname;
493 }
494
495 /**
496 * Returns unified '/' dirname including the last '/'
497 * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
498 */
499 public static String getDirname(String fname) throws URISyntaxException {
500 fname = slashify(fname, false /* startWithSlash */, false /* endWithSlash */);
501 final int lios = fname.lastIndexOf('/'); // strip off dirname
502 if(lios>=0) {
503 fname = fname.substring(0, lios+1);
504 }
505 return fname;
506 }
507
508 /***
509 *
510 * RESOURCE LOCATION HELPER
511 *
512 */
513
514 /**
515 * Helper compound associating a class instance and resource paths
516 * to be {@link #resolve(int) resolved} at a later time.
517 */
518 public static class ClassResources {
519 /** Optional {@link ClassLoader} used to {@link #resolve(int)} {@link #resourcePaths}. */
520 public final ClassLoader classLoader;
521
522 /** Optional class instance used to {@link #resolve(int)} relative {@link #resourcePaths}. */
523 public final Class<?> contextCL;
524
525 /** Resource paths, see {@link #resolve(int)}. */
526 public final String[] resourcePaths;
527
528 /** Returns the number of resources, i.e. <code>resourcePaths.length</code>. */
529 public final int resourceCount() { return resourcePaths.length; }
530
531 /**
532 * @param resourcePaths multiple relative or absolute resource locations
533 * @param classLoader optional {@link ClassLoader}, see {@link IOUtil#getResource(String, ClassLoader, Class)}
534 * @param relContext optional relative context, see {@link IOUtil#getResource(String, ClassLoader, Class)}
535 */
536 public ClassResources(final String[] resourcePaths, final ClassLoader classLoader, final Class<?> relContext) {
537 for(int i=resourcePaths.length-1; i>=0; i--) {
538 if( null == resourcePaths[i] ) {
539 throw new IllegalArgumentException("resourcePath["+i+"] is null");
540 }
541 }
542 this.classLoader = classLoader;
543 this.contextCL = relContext;
544 this.resourcePaths = resourcePaths;
545 }
546
547 /**
548 * Resolving one of the {@link #resourcePaths} indexed by <code>uriIndex</code> using
549 * {@link #classLoader}, {@link #contextCL} through {@link IOUtil#getResource(String, ClassLoader, Class)}.
550 * @throws ArrayIndexOutOfBoundsException if <code>uriIndex</code> is < 0 or >= {@link #resourceCount()}.
551 */
552 public URLConnection resolve(final int uriIndex) throws ArrayIndexOutOfBoundsException {
553 return getResource(resourcePaths[uriIndex], classLoader, contextCL);
554 }
555 }
556
557 /**
558 * Locating a resource using {@link #getResource(String, ClassLoader)}:
559 * <ul>
560 * <li><i>relative</i>: <code>relContext</code>'s package name-path plus <code>resourcePath</code> via <code>classLoader</code>.
561 * This allows locations relative to JAR- and other URLs.
562 * The <code>resourcePath</code> may start with <code>../</code> to navigate to parent folder.
563 * This attempt is skipped if {@code relContext} is {@code null}.</li>
564 * <li><i>absolute</i>: <code>resourcePath</code> as is via <code>classLoader</code>.
565 * </ul>
566 * <p>
567 * Returns the resolved and open URLConnection or null if not found.
568 * </p>
569 *
570 * @param resourcePath the resource path to locate relative or absolute
571 * @param classLoader the optional {@link ClassLoader}, recommended
572 * @param relContext relative context, i.e. position, of the {@code resourcePath},
573 * to perform the relative lookup, if not {@code null}.
574 * @see #getResource(String, ClassLoader)
575 * @see ClassLoader#getResource(String)
576 * @see ClassLoader#getSystemResource(String)
577 */
578 public static URLConnection getResource(final String resourcePath, final ClassLoader classLoader, final Class<?> relContext) {
579 if(null == resourcePath) {
580 return null;
581 }
582 URLConnection conn = null;
583 if(null != relContext) {
584 // scoping the path within the class's package
585 final String className = relContext.getName().replace('.', '/');
586 final int lastSlash = className.lastIndexOf('/');
587 if (lastSlash >= 0) {
588 final String pkgName = className.substring(0, lastSlash + 1);
589 conn = getResource(pkgName + resourcePath, classLoader);
590 if(DEBUG) {
591 System.err.println("IOUtil: found <"+resourcePath+"> within class package <"+pkgName+"> of given class <"+relContext.getName()+">: "+(null!=conn));
592 }
593 }
594 } else if(DEBUG) {
595 System.err.println("IOUtil: null context, skip rel. lookup");
596 }
597 if(null == conn) {
598 conn = getResource(resourcePath, classLoader);
599 if(DEBUG) {
600 System.err.println("IOUtil: found <"+resourcePath+"> by classloader: "+(null!=conn));
601 }
602 }
603 return conn;
604 }
605
606 /**
607 * Locating a resource using the ClassLoader's facilities.
608 * <p>
609 * Returns the resolved and connected URLConnection or null if not found.
610 * </p>
611 *
612 * @see ClassLoader#getResource(String)
613 * @see ClassLoader#getSystemResource(String)
614 * @see URL#URL(String)
615 * @see File#File(String)
616 */
617 public static URLConnection getResource(final String resourcePath, final ClassLoader cl) {
618 if(null == resourcePath) {
619 return null;
620 }
621 if(DEBUG) {
622 System.err.println("IOUtil: locating <"+resourcePath+">, has cl: "+(null!=cl));
623 }
624 if(resourcePath.startsWith(AssetURLContext.asset_protocol_prefix)) {
625 try {
626 return AssetURLContext.createURL(resourcePath, cl).openConnection();
627 } catch (final IOException ioe) {
628 if(DEBUG) {
629 ExceptionUtils.dumpThrowable("IOUtil", ioe);
630 }
631 return null;
632 }
633 } else {
634 try {
635 return AssetURLContext.resolve(resourcePath, cl);
636 } catch (final IOException ioe) {
637 if(DEBUG) {
638 ExceptionUtils.dumpThrowable("IOUtil", ioe);
639 }
640 }
641 }
642 return null;
643 }
644
645 /**
646 * Generates a path for the 'relativeFile' relative to the 'baseLocation'.
647 *
648 * @param baseLocation denotes a directory
649 * @param relativeFile denotes a relative file to the baseLocation
650 * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
651 */
652 public static String getRelativeOf(final File baseLocation, final String relativeFile) throws URISyntaxException {
653 if(null == relativeFile) {
654 return null;
655 }
656
657 if (baseLocation != null) {
658 final File file = new File(baseLocation, relativeFile);
659 // Handle things on Windows
660 return slashify(file.getPath(), false /* startWithSlash */, false /* endWithSlash */);
661 }
662 return null;
663 }
664
665 /**
666 * @param path assuming a slashified path, either denotes a file or directory, either relative or absolute.
667 * @return parent of path
668 * @throws URISyntaxException if path is empty or has no parent directory available
669 */
670 public static String getParentOf(final String path) throws URISyntaxException {
671 final int pl = null!=path ? path.length() : 0;
672 if(pl == 0) {
673 throw new IllegalArgumentException("path is empty <"+path+">");
674 }
675
676 final int e = path.lastIndexOf("/");
677 if( e < 0 ) {
678 throw new URISyntaxException(path, "path contains no '/': <"+path+">");
679 }
680 if( e == 0 ) {
681 // path is root directory
682 throw new URISyntaxException(path, "path has no parents: <"+path+">");
683 }
684 if( e < pl - 1 ) {
685 // path is file, return it's parent directory
686 return path.substring(0, e+1);
687 }
688 final int j = path.lastIndexOf("!") + 1; // '!' Separates JARFile entry -> local start of path
689 // path is a directory ..
690 final int p = path.lastIndexOf("/", e-1);
691 if( p >= j) {
692 // parent itself has '/' - post '!' or no '!' at all
693 return path.substring(0, p+1);
694 } else {
695 // parent itself has no '/'
696 final String parent = path.substring(j, e);
697 if( parent.equals("..") ) {
698 throw new URISyntaxException(path, "parent is unresolved: <"+path+">");
699 } else {
700 // parent is '!' or empty (relative path)
701 return path.substring(0, j);
702 }
703 }
704 }
705
706 /**
707 * @param path assuming a slashified path, either denoting a file or directory, either relative or absolute.
708 * @return clean path string where {@code ./} and {@code ../} is resolved,
709 * while keeping a starting {@code ../} at the beginning of a relative path.
710 * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
711 */
712 public static String cleanPathString(String path) throws URISyntaxException {
713 // Resolve './' before '../' to handle case 'parent/./../a.txt' properly.
714 int idx = path.length() - 1;
715 while ( idx >= 1 && ( idx = path.lastIndexOf("./", idx) ) >= 0 ) {
716 if( 0 < idx && path.charAt(idx-1) == '.' ) {
717 idx-=2; // skip '../' -> idx upfront
718 } else {
719 path = path.substring(0, idx) + path.substring(idx+2);
720 idx--; // idx upfront
721 }
722 }
723 idx = 0;
724 while ( ( idx = path.indexOf("../", idx) ) >= 0 ) {
725 if( 0 == idx ) {
726 idx += 3; // skip starting '../'
727 } else {
728 path = getParentOf(path.substring(0, idx)) + path.substring(idx+3);
729 idx = 0;
730 }
731 }
732 return path;
733 }
734
735 public static final Pattern patternSpaceEnc = Pattern.compile("%20");
736
737 /**
738 * If <code>uri</code> is a <i>file scheme</i>
739 * implementation returns {@link Uri#toFile()}.{@link File#getPath()}.
740 * <p>
741 * Otherwise it returns the {@link URI#toASCIIString()} encoded URI.
742 * </p>
743 */
744 public static String getUriFilePathOrASCII(final Uri uri) {
745 if( uri.isFileScheme() ) {
746 return uri.toFile().getPath();
747 } else {
748 return uri.toASCIIString().get();
749 }
750 }
751
752 /**
753 * Returns the connected URLConnection, or null if not url is not available
754 */
755 public static URLConnection openURL(final URL url) {
756 return openURL(url, ".");
757 }
758
759 /**
760 * Returns the connected URLConnection, or null if not url is not available
761 */
762 public static URLConnection openURL(final URL url, final String dbgmsg) {
763 if(null!=url) {
764 try {
765 final URLConnection c = url.openConnection();
766 c.connect(); // redundant
767 if(DEBUG) {
768 System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - true");
769 }
770 return c;
771 } catch (final IOException ioe) {
772 if(DEBUG) {
773 ExceptionUtils.dumpThrowable("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false -", ioe);
774 }
775 }
776 } else if(DEBUG) {
777 System.err.println("IOUtil: no url - urlExists(null) ["+dbgmsg+"]");
778 }
779
780 return null;
781 }
782
783 private static String getExeTestFileSuffix() {
784 switch(PlatformPropsImpl.OS_TYPE) {
785 case WINDOWS:
786 if( useNativeExeFile && Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family ) {
787 return ".exe";
788 } else {
789 return ".bat";
790 }
791 default:
792 return ".sh";
793 }
794 }
795 private static String getExeTestShellCode() {
796 switch(PlatformPropsImpl.OS_TYPE) {
797 case WINDOWS:
798 return "echo off"+PlatformPropsImpl.NEWLINE;
799 default:
800 return "#!/bin/true"+PlatformPropsImpl.NEWLINE;
801 }
802 }
803 private static String getExeNativePath(final String canonicalPath) {
804 switch(PlatformPropsImpl.OS_TYPE) {
805 case WINDOWS:
806 return "\""+canonicalPath+"\"";
807 default:
808 return canonicalPath;
809 }
810 }
811 private static String[] getExeTestCommandArgs(final String scriptFile) {
812 switch(PlatformPropsImpl.OS_TYPE) {
813 case WINDOWS:
814 // return new String[] { "cmd", "/c", scriptFile };
815 default:
816 return new String[] { scriptFile };
817 }
818 }
819
820 private static final byte[] readCode(final String fname) throws IOException {
821 final URLConnection con = IOUtil.getResource(fname, IOUtil.class.getClassLoader(), IOUtil.class);
822 final InputStream in = con.getInputStream();
823 byte[] output = null;
824 try {
825 output = CustomCompress.inflateFromStream(in);
826 } finally {
827 in.close();
828 }
829 return output;
830 }
831 private static final Object exeTestLock = new Object();
832 private static WeakReference<byte[]> exeTestCodeRef = null;
833
834 private static void fillExeTestFile(final File exefile) throws IOException {
835 if( useNativeExeFile &&
836 Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE &&
837 Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family
838 ) {
839 final byte[] exeTestCode;
840 synchronized ( exeTestLock ) {
841 byte[] _exeTestCode = null;
842 if( null == exeTestCodeRef || null == ( _exeTestCode = exeTestCodeRef.get() ) ) {
843 final String fname;
844 if( Platform.CPUType.X86_64 == PlatformPropsImpl.CPU_ARCH ) {
845 fname = "bin/exe-windows-x86_64.defl";
846 } else {
847 fname = "bin/exe-windows-i386.defl";
848 }
849 exeTestCode = readCode(fname);
850 exeTestCodeRef = new WeakReference<byte[]>(exeTestCode);
851 } else {
852 exeTestCode = _exeTestCode;
853 }
854 }
855 final FileOutputStream out = new FileOutputStream(exefile);
856 try {
857 out.write(exeTestCode, 0, exeTestCode.length);
858 try {
859 out.getFD().sync();
860 } catch (final SyncFailedException sfe) {
861 ExceptionUtils.dumpThrowable("", sfe);
862 }
863 } finally {
864 out.close();
865 }
866 } else {
867 final String shellCode = getExeTestShellCode();
868 if( isStringSet(shellCode) ) {
869 final FileWriter fout = new FileWriter(exefile);
870 try {
871 fout.write(shellCode);
872 try {
873 fout.flush();
874 } catch (final IOException sfe) {
875 ExceptionUtils.dumpThrowable("", sfe);
876 }
877 } finally {
878 fout.close();
879 }
880 }
881 }
882 }
883 private static boolean getOSHasNoexecFS() {
884 switch(PlatformPropsImpl.OS_TYPE) {
885 case OPENKODE:
886 return false;
887
888 default:
889 return true;
890 }
891 }
892
893 /**
894 * @see <a href="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">Free-Desktop - XDG Base Directory Specification</a>
895 */
896 private static boolean getOSHasFreeDesktopXDG() {
897 switch(PlatformPropsImpl.OS_TYPE) {
898 case ANDROID:
899 case MACOS:
900 case IOS:
901 case WINDOWS:
902 case OPENKODE:
903 return false;
904
905 default:
906 return true;
907 }
908 }
909
910 /**
911 * Test whether {@code file} exists and matches the given requirements
912 *
913 * @param file
914 * @param shallBeDir
915 * @param shallBeWritable
916 * @return
917 */
918 public static boolean testFile(final File file, final boolean shallBeDir, final boolean shallBeWritable) {
919 if (!file.exists()) {
920 if(DEBUG) {
921 System.err.println("IOUtil.testFile: <"+file.getAbsolutePath()+">: does not exist");
922 }
923 return false;
924 }
925 if (shallBeDir && !file.isDirectory()) {
926 if(DEBUG) {
927 System.err.println("IOUtil.testFile: <"+file.getAbsolutePath()+">: is not a directory");
928 }
929 return false;
930 }
931 if (shallBeWritable && !file.canWrite()) {
932 if(DEBUG) {
933 System.err.println("IOUtil.testFile: <"+file.getAbsolutePath()+">: is not writable");
934 }
935 return false;
936 }
937 return true;
938 }
939
940 public static class StreamMonitor implements Runnable {
941 private final InputStream[] istreams;
942 private final boolean[] eos;
943 private final PrintStream ostream;
944 private final String prefix;
945 public StreamMonitor(final InputStream[] streams, final PrintStream ostream, final String prefix) {
946 this.istreams = streams;
947 this.eos = new boolean[streams.length];
948 this.ostream = ostream;
949 this.prefix = prefix;
950 final InterruptSource.Thread t = new InterruptSource.Thread(null, this, "StreamMonitor-"+Thread.currentThread().getName());
951 t.setDaemon(true);
952 t.start();
953 }
954
955 @Override
956 public void run()
957 {
958 final byte[] buffer = new byte[4096];
959 try {
960 final int streamCount = istreams.length;
961 int eosCount = 0;
962 do {
963 for(int i=0; i<istreams.length; i++) {
964 if( !eos[i] ) {
965 final int numReadI = istreams[i].read(buffer);
966 if (numReadI > 0) {
967 if( null != ostream ) {
968 if( null != prefix ) {
969 ostream.write(prefix.getBytes());
970 }
971 ostream.write(buffer, 0, numReadI);
972 }
973 } else {
974 // numReadI == -1
975 eosCount++;
976 eos[i] = true;
977 }
978 }
979 }
980 if( null != ostream ) {
981 ostream.flush();
982 }
983 } while ( eosCount < streamCount );
984 } catch (final IOException e) {
985 } finally {
986 if( null != ostream ) {
987 ostream.flush();
988 }
989 // Should allow clean exit when process shuts down
990 }
991 }
992 }
993
994 private static final Boolean isNioExecutableFile(final File file) {
995 if( null != fileToPathGetter && null != isExecutableQuery ) {
996 try {
997 return (Boolean) isExecutableQuery.invoke(null, fileToPathGetter.invoke(file));
998 } catch (final Throwable t) {
999 throw new JogampRuntimeException("error invoking Files.isExecutable(file.toPath())", t);
1000 }
1001 } else {
1002 return null;
1003 }
1004 }
1005
1006 /**
1007 * Returns true if the given {@code dir}
1008 * <ol>
1009 * <li>exists, and</li>
1010 * <li>is a directory, and</li>
1011 * <li>is writeable, and</li>
1012 * <li>files can be executed from the directory</li>
1013 * </ol>
1014 *
1015 * @throws SecurityException if file creation and process execution is not allowed within the current security context
1016 * @param dir
1017 */
1018 public static boolean testDirExec(final File dir)
1019 throws SecurityException
1020 {
1021 final boolean debug = DEBUG_EXE || DEBUG;
1022
1023 if( !testTempDirExec ) {
1024 if(DEBUG) {
1025 System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Disabled TestTempDirExec");
1026 }
1027 return false;
1028 }
1029 if (!testFile(dir, true, true)) {
1030 if( debug ) {
1031 System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Not writeable dir");
1032 }
1033 return false;
1034 }
1035 if(!getOSHasNoexecFS()) {
1036 if( debug ) {
1037 System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Always executable");
1038 }
1039 return true;
1040 }
1041
1042 final long t0 = debug ? System.currentTimeMillis() : 0;
1043 final File exeTestFile;
1044 String exeNativePath;
1045 final boolean existingExe;
1046 try {
1047 final File permExeTestFile = DEBUG_EXE_EXISTING_FILE ? new File(dir, "jogamp_exe_tst"+getExeTestFileSuffix()) : null;
1048 if( null != permExeTestFile && permExeTestFile.exists() ) {
1049 exeTestFile = permExeTestFile;
1050 existingExe = true;
1051 } else {
1052 exeTestFile = File.createTempFile("jogamp_exe_tst", getExeTestFileSuffix(), dir);
1053 existingExe = false;
1054 fillExeTestFile(exeTestFile);
1055 }
1056 exeNativePath = getExeNativePath( exeTestFile.getCanonicalPath() );
1057 } catch (final SecurityException se) {
1058 throw se; // fwd Security exception
1059 } catch (final IOException e) {
1060 if( debug ) {
1061 e.printStackTrace();
1062 }
1063 return false;
1064 }
1065 final long t1 = debug ? System.currentTimeMillis() : 0;
1066 long t2;
1067 int res = -1;
1068 int exitValue = -1;
1069 Boolean isNioExec = null;
1070 if( existingExe || exeTestFile.setExecutable(true /* exec */, true /* ownerOnly */) ) {
1071 t2 = debug ? System.currentTimeMillis() : 0;
1072 // First soft exec test via NIO's ACL check, if available
1073 isNioExec = isNioExecutableFile(exeTestFile);
1074 if( null != isNioExec ) {
1075 res = isNioExec.booleanValue() ? 0 : -1;
1076 }
1077 if( null == isNioExec || 0 <= res ) {
1078 // Hard exec test via actual execution, if NIO's ACL check succeeded or not available.
1079 // Required, since Windows 'Software Restriction Policies (SRP)' won't be triggered merely by NIO's ACL check.
1080 Process pr = null;
1081 try {
1082 // Using 'Process.exec(String[])' avoids StringTokenizer of 'Process.exec(String)'
1083 // and hence splitting up command by spaces!
1084 // Note: All no-exec cases throw an IOExceptions at ProcessBuilder.start(), i.e. below exec() call!
1085 pr = Runtime.getRuntime().exec( getExeTestCommandArgs( exeNativePath ), null, null );
1086 if( DEBUG_EXE && !DEBUG_EXE_NOSTREAM ) {
1087 new StreamMonitor(new InputStream[] { pr.getInputStream(), pr.getErrorStream() }, System.err, "Exe-Tst: ");
1088 }
1089 pr.waitFor();
1090 exitValue = pr.exitValue(); // Note: Bug 1219 Comment 50: On reporter's machine exit value 1 is being returned
1091 if( 0 == exitValue ) {
1092 res++; // file has been executed and exited normally
1093 } else {
1094 res = -2; // abnormal termination
1095 }
1096 } catch (final SecurityException se) {
1097 throw se; // fwd Security exception
1098 } catch (final Throwable t) {
1099 t2 = debug ? System.currentTimeMillis() : 0;
1100 res = -3;
1101 if( debug ) {
1102 System.err.println("IOUtil.testDirExec: <"+exeNativePath+">: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
1103 t.printStackTrace();
1104 }
1105 } finally {
1106 if( null != pr ) {
1107 // Bug 1219 Comment 58: Ensure that the launched process gets terminated!
1108 // This is Process implementation specific and varies on different platforms,
1109 // hence it may be required.
1110 try {
1111 pr.destroy();
1112 } catch (final Throwable t) {
1113 ExceptionUtils.dumpThrowable("", t);
1114 }
1115 }
1116 }
1117 }
1118 } else {
1119 t2 = debug ? System.currentTimeMillis() : 0;
1120 }
1121
1122 final boolean ok = 0 <= res;
1123 if( !DEBUG_EXE && !existingExe ) {
1124 exeTestFile.delete();
1125 }
1126 if( debug ) {
1127 final long t3 = System.currentTimeMillis();
1128 System.err.println("IOUtil.testDirExec(): test-exe <"+exeNativePath+">, existingFile "+existingExe+", isNioExec "+isNioExec+", returned "+exitValue);
1129 System.err.println("IOUtil.testDirExec(): abs-path <"+dir.getAbsolutePath()+">: res "+res+" -> "+ok);
1130 System.err.println("IOUtil.testDirExec(): total "+(t3-t0)+"ms, create "+(t1-t0)+"ms, fill "+(t2-t1)+"ms, execute "+(t3-t2)+"ms");
1131 }
1132 return ok;
1133 }
1134
1135 private static File testDirImpl(final File dir, final boolean create, final boolean executable, final String dbgMsg)
1136 throws SecurityException
1137 {
1138 final File res;
1139 if (create && !dir.exists()) {
1140 dir.mkdirs();
1141 }
1142 if( executable ) {
1143 res = testDirExec(dir) ? dir : null;
1144 } else {
1145 res = testFile(dir, true, true) ? dir : null;
1146 }
1147 if(DEBUG) {
1148 System.err.println("IOUtil.testDirImpl("+dbgMsg+"): <"+dir.getAbsolutePath()+">, create "+create+", exec "+executable+": "+(null != res));
1149 }
1150 return res;
1151 }
1152
1153 /**
1154 * Returns the directory {@code dir}, which is processed and tested as described below.
1155 * <ol>
1156 * <li>If {@code create} is {@code true} and the directory does not exist yet, it is created incl. all sub-directories.</li>
1157 * <li>If {@code dirName} exists, but is not a directory, {@code null} is being returned.</li>
1158 * <li>If the directory does not exist or is not writeable, {@code null} is being returned.</li>
1159 * <li>If {@code executable} is {@code true} and files cannot be executed from the directory, {@code null} is being returned.</li>
1160 * </ol>
1161 *
1162 * @param dir the directory to process
1163 * @param create true if the directory shall be created if not existing
1164 * @param executable true if the user intents to launch executables from the temporary directory, otherwise false.
1165 * @throws SecurityException if file creation and process execution is not allowed within the current security context
1166 */
1167 public static File testDir(final File dir, final boolean create, final boolean executable)
1168 throws SecurityException
1169 {
1170 return testDirImpl(dir, create, executable, "testDir");
1171 }
1172
1173 private static boolean isStringSet(final String s) { return null != s && 0 < s.length(); }
1174
1175 /**
1176 * This methods finds [and creates] an available temporary sub-directory:
1177 * <pre>
1178 File tmpBaseDir = null;
1179 if(null != testDir(tmpRoot, true, executable)) { // check tmpRoot first
1180 for(int i = 0; null == tmpBaseDir && i<=9999; i++) {
1181 final String tmpDirSuffix = String.format("_%04d", i); // 4 digits for iteration
1182 tmpBaseDir = testDir(new File(tmpRoot, tmpSubDirPrefix+tmpDirSuffix), true, executable);
1183 }
1184 } else {
1185 tmpBaseDir = null;
1186 }
1187 return tmpBaseDir;
1188 * </pre>
1189 * <p>
1190 * The iteration through [0000-9999] ensures that the code is multi-user save.
1191 * </p>
1192 * @param tmpRoot
1193 * @param executable
1194 * @param dbgMsg
1195 * @param tmpDirPrefix
1196 * @return a temporary directory, writable by this user
1197 * @throws SecurityException
1198 */
1199 private static File getSubTempDir(final File tmpRoot, final String tmpSubDirPrefix, final boolean executable, final String dbgMsg)
1200 throws SecurityException
1201 {
1202 File tmpBaseDir = null;
1203 if(null != testDirImpl(tmpRoot, true /* create */, executable, dbgMsg)) { // check tmpRoot first
1204 for(int i = 0; null == tmpBaseDir && i<=9999; i++) {
1205 final String tmpDirSuffix = String.format((Locale)null, "_%04d", i); // 4 digits for iteration
1206 tmpBaseDir = testDirImpl(new File(tmpRoot, tmpSubDirPrefix+tmpDirSuffix), true /* create */, executable, dbgMsg);
1207 }
1208 }
1209 return tmpBaseDir;
1210 }
1211
1212 private static File getFile(final String fname) {
1213 if( isStringSet(fname) ) {
1214 return new File(fname);
1215 } else {
1216 return null;
1217 }
1218
1219 }
1220 /**
1221 * Returns a platform independent writable directory for temporary files
1222 * consisting of the platform's {@code temp-root} + {@link #tmpSubDir},
1223 * e.g. {@code /tmp/jogamp_0000/}.
1224 * <p>
1225 * On standard Java the {@code temp-root} folder is specified by <code>java.io.tempdir</code>.
1226 * </p>
1227 * <p>
1228 * On Android the {@code temp-root} folder is relative to the applications local folder
1229 * (see {@link Context#getDir(String, int)}) is returned, if
1230 * the Android application/activity has registered it's Application Context
1231 * via {@link jogamp.common.os.android.StaticContext.StaticContext#init(Context, ClassLoader) StaticContext.init(..)}.
1232 * This allows using the temp folder w/o the need for <code>sdcard</code>
1233 * access, which would be the <code>java.io.tempdir</code> location on Android!
1234 * </p>
1235 * <p>
1236 * In case {@code temp-root} is the users home folder,
1237 * a dot is being prepended to {@link #tmpSubDir}, i.e.: {@code /home/user/.jogamp_0000/}.
1238 * </p>
1239 * @param executable true if the user intents to launch executables from the temporary directory, otherwise false.
1240 * @throws IOException if no temporary directory could be determined
1241 * @throws SecurityException if access to <code>java.io.tmpdir</code> is not allowed within the current security context
1242 *
1243 * @see PropertyAccess#getProperty(String, boolean)
1244 * @see Context#getDir(String, int)
1245 */
1246 public static File getTempDir(final boolean executable)
1247 throws SecurityException, IOException
1248 {
1249 if(!tempRootSet) { // volatile: ok
1250 synchronized(IOUtil.class) {
1251 if(!tempRootSet) {
1252 tempRootSet = true;
1253 {
1254 final File ctxTempDir = AndroidUtils.getTempRoot(); // null if ( !Android || no android-ctx )
1255 if(null != ctxTempDir) {
1256 tempRootNoexec = getSubTempDir(ctxTempDir, tmpSubDir, false /* executable, see below */, "Android.ctxTemp");
1257 tempRootExec = tempRootNoexec; // FIXME: Android temp root is always executable (?)
1258 return tempRootExec;
1259 }
1260 }
1261
1262 final File java_io_tmpdir = getFile( PropertyAccess.getProperty(java_io_tmpdir_propkey, false) );
1263 if(DEBUG) {
1264 System.err.println("IOUtil.getTempRoot(): tempX1 <"+java_io_tmpdir+">, used "+(null!=java_io_tmpdir));
1265 }
1266
1267 final File user_tmpdir; // only if diff than java_io_tmpdir
1268 {
1269 String __user_tmpdir = System.getenv("TMPDIR");
1270 if( !isStringSet(__user_tmpdir) ) {
1271 __user_tmpdir = System.getenv("TEMP");
1272 }
1273 final File _user_tmpdir = getFile(__user_tmpdir);
1274 if( null != _user_tmpdir && !_user_tmpdir.equals(java_io_tmpdir) ) {
1275 user_tmpdir = _user_tmpdir;
1276 } else {
1277 user_tmpdir = null;
1278 }
1279 if(DEBUG) {
1280 System.err.println("IOUtil.getTempRoot(): tempX3 <"+_user_tmpdir+">, used "+(null!=user_tmpdir));
1281 }
1282 }
1283
1284 final File user_home = getFile( PropertyAccess.getProperty(user_home_propkey, false) );
1285 if(DEBUG) {
1286 System.err.println("IOUtil.getTempRoot(): tempX4 <"+user_home+">, used "+(null!=user_home));
1287 }
1288
1289 final File xdg_cache_home;
1290 {
1291 String __xdg_cache_home;
1292 if( getOSHasFreeDesktopXDG() ) {
1293 __xdg_cache_home = System.getenv(XDG_CACHE_HOME_envkey);
1294 if( !isStringSet(__xdg_cache_home) && null != user_home ) {
1295 __xdg_cache_home = user_home.getAbsolutePath() + File.separator + ".cache" ; // default
1296 }
1297 } else {
1298 __xdg_cache_home = null;
1299 }
1300 final File _xdg_cache_home = getFile(__xdg_cache_home);
1301 if( null != _xdg_cache_home && !_xdg_cache_home.equals(java_io_tmpdir) ) {
1302 xdg_cache_home = _xdg_cache_home;
1303 } else {
1304 xdg_cache_home = null;
1305 }
1306 if(DEBUG) {
1307 System.err.println("IOUtil.getTempRoot(): tempX2 <"+_xdg_cache_home+">, used "+(null!=xdg_cache_home));
1308 }
1309 }
1310
1311 // 1) java.io.tmpdir/jogamp
1312 if( null == tempRootExec && null != java_io_tmpdir ) {
1313 if( Platform.OSType.MACOS == PlatformPropsImpl.OS_TYPE || Platform.OSType.IOS == PlatformPropsImpl.OS_TYPE ) {
1314 // Bug 865: Safari >= 6.1 [OSX] May employ xattr on 'com.apple.quarantine' on 'PluginProcess.app'
1315 // We attempt to fix this issue _after_ gluegen native lib is loaded, see JarUtil.fixNativeLibAttribs(File).
1316 tempRootExec = getSubTempDir(java_io_tmpdir, tmpSubDir, false /* executable */, "tempX1");
1317 } else {
1318 tempRootExec = getSubTempDir(java_io_tmpdir, tmpSubDir, true /* executable */, "tempX1");
1319 }
1320 }
1321
1322 // 2) $XDG_CACHE_HOME/jogamp
1323 if( null == tempRootExec && null != xdg_cache_home ) {
1324 tempRootExec = getSubTempDir(xdg_cache_home, tmpSubDir, true /* executable */, "tempX2");
1325 }
1326
1327 // 3) $TMPDIR/jogamp
1328 if( null == tempRootExec && null != user_tmpdir ) {
1329 tempRootExec = getSubTempDir(user_tmpdir, tmpSubDir, true /* executable */, "tempX3");
1330 }
1331
1332 // 4) $HOME/.jogamp
1333 if( null == tempRootExec && null != user_home ) {
1334 tempRootExec = getSubTempDir(user_home, "." + tmpSubDir, true /* executable */, "tempX4");
1335 }
1336
1337 if( null != tempRootExec ) {
1338 tempRootNoexec = tempRootExec;
1339 } else {
1340 // 1) java.io.tmpdir/jogamp
1341 if( null == tempRootNoexec && null != java_io_tmpdir ) {
1342 tempRootNoexec = getSubTempDir(java_io_tmpdir, tmpSubDir, false /* executable */, "temp01");
1343 }
1344
1345 // 2) $XDG_CACHE_HOME/jogamp
1346 if( null == tempRootNoexec && null != xdg_cache_home ) {
1347 tempRootNoexec = getSubTempDir(xdg_cache_home, tmpSubDir, false /* executable */, "temp02");
1348 }
1349
1350 // 3) $TMPDIR/jogamp
1351 if( null == tempRootNoexec && null != user_tmpdir ) {
1352 tempRootNoexec = getSubTempDir(user_tmpdir, tmpSubDir, false /* executable */, "temp03");
1353 }
1354
1355 // 4) $HOME/.jogamp
1356 if( null == tempRootNoexec && null != user_home ) {
1357 tempRootNoexec = getSubTempDir(user_home, "." + tmpSubDir, false /* executable */, "temp04");
1358 }
1359 }
1360
1361 if(DEBUG) {
1362 final String tempRootExecAbsPath = null != tempRootExec ? tempRootExec.getAbsolutePath() : null;
1363 final String tempRootNoexecAbsPath = null != tempRootNoexec ? tempRootNoexec.getAbsolutePath() : null;
1364 System.err.println("IOUtil.getTempRoot(): temp dirs: exec: "+tempRootExecAbsPath+", noexec: "+tempRootNoexecAbsPath);
1365 }
1366 }
1367 }
1368 }
1369 final File r = executable ? tempRootExec : tempRootNoexec ;
1370 if(null == r) {
1371 final String exe_s = executable ? "executable " : "";
1372 throw new IOException("Could not determine a temporary "+exe_s+"directory");
1373 }
1374 final FilePermission fp = new FilePermission(r.getAbsolutePath(), "read,write,delete");
1375 SecurityUtil.checkPermission(fp);
1376 return r;
1377 }
1378 private static File tempRootExec = null; // writeable and executable
1379 private static File tempRootNoexec = null; // writeable, maybe executable
1380 private static volatile boolean tempRootSet = false;
1381
1382 /**
1383 * Utilizing {@link File#createTempFile(String, String, File)} using
1384 * {@link #getTempDir(boolean)} as the directory parameter, ie. location
1385 * of the root temp folder.
1386 *
1387 * @see File#createTempFile(String, String)
1388 * @see File#createTempFile(String, String, File)
1389 * @see #getTempDir(boolean)
1390 *
1391 * @param prefix
1392 * @param suffix
1393 * @param executable true if the temporary root folder needs to hold executable files, otherwise false.
1394 * @return
1395 * @throws IllegalArgumentException
1396 * @throws IOException if no temporary directory could be determined or temp file could not be created
1397 * @throws SecurityException
1398 */
1399 public static File createTempFile(final String prefix, final String suffix, final boolean executable)
1400 throws IllegalArgumentException, IOException, SecurityException
1401 {
1402 return File.createTempFile( prefix, suffix, getTempDir(executable) );
1403 }
1404
1405 public static void close(final Closeable stream, final boolean throwRuntimeException) throws RuntimeException {
1406 if(null != stream) {
1407 try {
1408 stream.close();
1409 } catch (final IOException e) {
1410 if(throwRuntimeException) {
1411 throw new RuntimeException(e);
1412 } else if(DEBUG) {
1413 System.err.println("Caught Exception: ");
1414 e.printStackTrace();
1415 }
1416 }
1417 }
1418 }
1419
1420 /**
1421 * Helper to simplify closing {@link Closeable}s.
1422 *
1423 * @param stream the {@link Closeable} instance to close
1424 * @param saveOneIfFree cache for one {@link IOException} to store, if not already used (excess)
1425 * @param dumpExcess dump the excess {@link IOException} on this {@link PrintStream}
1426 * @return the excess {@link IOException} or {@code null}.
1427 */
1428 public static IOException close(final Closeable stream, final IOException[] saveOneIfFree, final PrintStream dumpExcess) {
1429 try {
1430 stream.close();
1431 } catch(final IOException e) {
1432 if( null == saveOneIfFree[0] ) {
1433 saveOneIfFree[0] = e;
1434 } else {
1435 if( null != dumpExcess ) {
1436 dumpExcess.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage());
1437 e.printStackTrace(dumpExcess);
1438 }
1439 return e;
1440 }
1441 }
1442 return null;
1443 }
1444
1445 /**
1446 * Retrieve the list of all filenames traversing through given paths
1447 * @param paths list of paths to traverse through, containing directories and files
1448 * @param excludes optional list of exclude {@link Pattern}. All {@link Pattern#matcher(CharSequence) matching} files or directories will be omitted. Maybe be null or empty.
1449 * @param includes optional list of explicit include {@link Pattern}. If given, only {@link Pattern#matcher(CharSequence) matching} files will be returned, otherwise all occurring.
1450 * @return list of unsorted filenames within given paths
1451 */
1452 public static ArrayList<String> filesOf(final List<String> paths, final List<Pattern> excludes, final List<Pattern> includes) {
1453 final ArrayList<String> files = new ArrayList<String>(paths.size()*32);
1454 final ArrayList<String> todo = new ArrayList<String>(paths);
1455 while(todo.size() > 0) {
1456 final String p = todo.remove(0);
1457 if( null != excludes && excludes.size() > 0) {
1458 boolean exclude = false;
1459 for(int i=0; !exclude && i<excludes.size(); i++) {
1460 exclude = excludes.get(i).matcher(p).matches();
1461 if( DEBUG ) {
1462 if( exclude ) {
1463 System.err.println("IOUtil.filesOf(): excluding <"+p+"> (exclude["+i+"]: "+excludes.get(i)+")");
1464 }
1465 }
1466 }
1467 if( exclude ) {
1468 continue; // skip further processing, continue w/ next path
1469 }
1470 }
1471 final File f = new File(p);
1472 if( !f.exists() ) {
1473 if( DEBUG ) {
1474 System.err.println("IOUtil.filesOf(): not existing: "+f);
1475 }
1476 continue;
1477 } else if( f.isDirectory() ) {
1478 final String[] subs = f.list();
1479 if( null == subs ) {
1480 if( DEBUG ) {
1481 System.err.println("IOUtil.filesOf(): null list of directory: "+f);
1482 }
1483 } else if( 0 == subs.length ) {
1484 if( DEBUG ) {
1485 System.err.println("IOUtil.filesOf(): empty list of directory: "+f);
1486 }
1487 } else {
1488 int j=0;
1489 final String pp = p.endsWith("/") ? p : p+"/";
1490 for(int i=0; i<subs.length; i++) {
1491 todo.add(j++, pp+subs[i]); // add 'in-place' to soothe the later sorting algorithm
1492 }
1493 }
1494 } else {
1495 if( null != includes && includes.size() > 0) {
1496 boolean include = false;
1497 for(int i=0; !include && i<includes.size(); i++) {
1498 include = includes.get(i).matcher(p).matches();
1499 if( DEBUG ) {
1500 if( include ) {
1501 System.err.println("IOUtil.filesOf(): including <"+p+"> (including["+i+"]: "+includes.get(i)+")");
1502 }
1503 }
1504 }
1505 if( include ) {
1506 files.add(p);
1507 }
1508 } else {
1509 files.add(p);
1510 }
1511 }
1512 }
1513 return files;
1514 }
1515}
com.jogamp.common.ExceptionUtils
Definition: ExceptionUtils.java:35
com.jogamp.common.ExceptionUtils.dumpThrowable
static void dumpThrowable(final String additionalDescr, final Throwable t)
Dumps a Throwable to System.err in a decorating message including the current thread name,...
Definition: ExceptionUtils.java:135
com.jogamp.common.JogampRuntimeException
A generic unchecked exception for Jogamp errors used throughout the binding as a substitute for Runti...
Definition: JogampRuntimeException.java:36
com.jogamp.common.net.AssetURLContext
See PiggybackURLConnection for description and examples.
Definition: AssetURLContext.java:18
com.jogamp.common.net.AssetURLContext.asset_protocol_prefix
static final String asset_protocol_prefix
The asset URL protocol prefix asset:
Definition: AssetURLContext.java:25
com.jogamp.common.net.AssetURLContext.createURL
static URL createURL(final String path, final ClassLoader cl)
Create an asset URL, suitable even w/o the registered asset URLStreamHandler.
Definition: AssetURLContext.java:62
com.jogamp.common.net.AssetURLContext.resolve
URLConnection resolve(final String path)
Resolving path to a URL sub protocol and return it's open URLConnection.
Definition: AssetURLContext.java:144
com.jogamp.common.net.Uri.Encoded.get
final String get()
Returns the encoded String.
Definition: Uri.java:336
com.jogamp.common.net.Uri
This class implements an immutable Uri as defined by RFC 2396.
Definition: Uri.java:160
com.jogamp.common.net.Uri.toASCIIString
ASCIIEncoded toASCIIString()
Returns the encoded input encoded in US-ASCII.
Definition: Uri.java:1308
com.jogamp.common.net.Uri.isFileScheme
final boolean isFileScheme()
Returns true, if this instance is a file scheme, otherwise false.
Definition: Uri.java:1255
com.jogamp.common.net.Uri.toFile
final File toFile()
If this instance is a file scheme, implementation decodes [ "//"+authority ] + path,...
Definition: Uri.java:1390
com.jogamp.common.nio.Buffers
Utility methods allowing easy java.nio.Buffer manipulations.
Definition: Buffers.java:70
com.jogamp.common.nio.Buffers.newDirectByteBuffer
static ByteBuffer newDirectByteBuffer(final int numElements)
Allocates a new direct ByteBuffer with the specified number of elements.
Definition: Buffers.java:92
com.jogamp.common.os.MachineDataInfo
Machine data description for alignment and size onle, see com.jogamp.gluegen.
Definition: MachineDataInfo.java:57
com.jogamp.common.os.MachineDataInfo.pageAlignedSize
int pageAlignedSize(final int size)
Definition: MachineDataInfo.java:305
com.jogamp.common.os.Platform
Utility class for querying platform specific properties.
Definition: Platform.java:58
com.jogamp.common.os.Platform.getMachineDataInfo
static MachineDataInfo getMachineDataInfo()
Returns the MachineDataInfo of the running machine.
Definition: Platform.java:510
com.jogamp.common.util.IOUtil.ClassResources
Helper compound associating a class instance and resource paths to be resolved at a later time.
Definition: IOUtil.java:518
com.jogamp.common.util.IOUtil.ClassResources.resourceCount
final int resourceCount()
Returns the number of resources, i.e.
Definition: IOUtil.java:529
com.jogamp.common.util.IOUtil.ClassResources.resourcePaths
final String[] resourcePaths
Resource paths, see resolve(int).
Definition: IOUtil.java:526
com.jogamp.common.util.IOUtil.ClassResources.resolve
URLConnection resolve(final int uriIndex)
Resolving one of the resourcePaths indexed by uriIndex using classLoader, contextCL through IOUtil#ge...
Definition: IOUtil.java:552
com.jogamp.common.util.IOUtil.ClassResources.classLoader
final ClassLoader classLoader
Optional ClassLoader used to resolve(int) resourcePaths.
Definition: IOUtil.java:520
com.jogamp.common.util.IOUtil.ClassResources.ClassResources
ClassResources(final String[] resourcePaths, final ClassLoader classLoader, final Class<?> relContext)
Definition: IOUtil.java:536
com.jogamp.common.util.IOUtil.ClassResources.contextCL
final Class<?> contextCL
Optional class instance used to resolve(int) relative resourcePaths.
Definition: IOUtil.java:523
com.jogamp.common.util.IOUtil.StreamMonitor
Definition: IOUtil.java:940
com.jogamp.common.util.IOUtil.StreamMonitor.StreamMonitor
StreamMonitor(final InputStream[] streams, final PrintStream ostream, final String prefix)
Definition: IOUtil.java:945
com.jogamp.common.util.IOUtil.StreamMonitor.run
void run()
Definition: IOUtil.java:956
com.jogamp.common.util.IOUtil
Definition: IOUtil.java:69
com.jogamp.common.util.IOUtil.getFileOutputStream
static FileOutputStream getFileOutputStream(final File file, final boolean allowOverwrite)
Definition: IOUtil.java:448
com.jogamp.common.util.IOUtil.cleanPathString
static String cleanPathString(String path)
Definition: IOUtil.java:712
com.jogamp.common.util.IOUtil.copyStream2Stream
static int copyStream2Stream(final int bufferSize, final InputStream in, final OutputStream out)
Copy the complete specified input stream to the specified output stream.
Definition: IOUtil.java:236
com.jogamp.common.util.IOUtil.copyStream2ByteBuffer
static ByteBuffer copyStream2ByteBuffer(InputStream stream, int initialCapacity)
Copy the complete specified input stream to a NIO ByteBuffer w/ native byte order,...
Definition: IOUtil.java:307
com.jogamp.common.util.IOUtil.createTempFile
static File createTempFile(final String prefix, final String suffix, final boolean executable)
Utilizing File#createTempFile(String, String, File) using getTempDir(boolean) as the directory parame...
Definition: IOUtil.java:1399
com.jogamp.common.util.IOUtil.getBasename
static String getBasename(String fname)
Returns the basename of the given fname w/o directory part.
Definition: IOUtil.java:486
com.jogamp.common.util.IOUtil.tmpSubDir
static final String tmpSubDir
Subdirectory within platform's temporary root directory where all JogAmp related temp files are being...
Definition: IOUtil.java:132
com.jogamp.common.util.IOUtil.getClassURL
static URL getClassURL(final String clazzBinName, final ClassLoader cl)
Definition: IOUtil.java:474
com.jogamp.common.util.IOUtil.openURL
static URLConnection openURL(final URL url, final String dbgmsg)
Returns the connected URLConnection, or null if not url is not available.
Definition: IOUtil.java:762
com.jogamp.common.util.IOUtil.getResource
static URLConnection getResource(final String resourcePath, final ClassLoader cl)
Locating a resource using the ClassLoader's facilities.
Definition: IOUtil.java:617
com.jogamp.common.util.IOUtil.DEBUG
static final boolean DEBUG
Definition: IOUtil.java:70
com.jogamp.common.util.IOUtil.testFile
static boolean testFile(final File file, final boolean shallBeDir, final boolean shallBeWritable)
Test whether file exists and matches the given requirements.
Definition: IOUtil.java:918
com.jogamp.common.util.IOUtil.getResource
static URLConnection getResource(final String resourcePath, final ClassLoader classLoader, final Class<?> relContext)
Locating a resource using getResource(String, ClassLoader):
Definition: IOUtil.java:578
com.jogamp.common.util.IOUtil.getRelativeOf
static String getRelativeOf(final File baseLocation, final String relativeFile)
Generates a path for the 'relativeFile' relative to the 'baseLocation'.
Definition: IOUtil.java:652
com.jogamp.common.util.IOUtil.getTempDir
static File getTempDir(final boolean executable)
Returns a platform independent writable directory for temporary files consisting of the platform's te...
Definition: IOUtil.java:1246
com.jogamp.common.util.IOUtil.getParentOf
static String getParentOf(final String path)
Definition: IOUtil.java:670
com.jogamp.common.util.IOUtil.copyStream2Stream
static int copyStream2Stream(final InputStream in, final OutputStream out)
Copy the complete specified input stream to the specified output stream.
Definition: IOUtil.java:222
com.jogamp.common.util.IOUtil.getFileSuffix
static String getFileSuffix(final File file)
Returns the lowercase suffix of the given file name (the text after the last '.
Definition: IOUtil.java:411
com.jogamp.common.util.IOUtil.slashify
static String slashify(final String path, final boolean startWithSlash, final boolean endWithSlash)
Definition: IOUtil.java:389
com.jogamp.common.util.IOUtil.openURL
static URLConnection openURL(final URL url)
Returns the connected URLConnection, or null if not url is not available.
Definition: IOUtil.java:755
com.jogamp.common.util.IOUtil.copyStream2ByteBuffer
static ByteBuffer copyStream2ByteBuffer(final InputStream stream)
Copy the complete specified input stream to a NIO ByteBuffer w/ native byte order,...
Definition: IOUtil.java:297
com.jogamp.common.util.IOUtil.close
static void close(final Closeable stream, final boolean throwRuntimeException)
Definition: IOUtil.java:1405
com.jogamp.common.util.IOUtil.getClassFileName
static String getClassFileName(final String clazzBinName)
Definition: IOUtil.java:463
com.jogamp.common.util.IOUtil.getDirname
static String getDirname(String fname)
Returns unified '/' dirname including the last '/'.
Definition: IOUtil.java:499
com.jogamp.common.util.IOUtil.copyStreamChunk2ByteBuffer
static ByteBuffer copyStreamChunk2ByteBuffer(InputStream stream, int skipBytes, int byteCount)
Copy the specified input stream chunk to a NIO ByteBuffer w/ native byte order, which is being return...
Definition: IOUtil.java:347
com.jogamp.common.util.IOUtil.getFileSuffix
static String getFileSuffix(final String filename)
Returns the lowercase suffix of the given file name (the text after the last '.
Definition: IOUtil.java:425
com.jogamp.common.util.IOUtil.testDirExec
static boolean testDirExec(final File dir)
Returns true if the given dir @endiliteral.
Definition: IOUtil.java:1018
com.jogamp.common.util.IOUtil.patternSpaceEnc
static final Pattern patternSpaceEnc
Definition: IOUtil.java:735
com.jogamp.common.util.IOUtil.testDir
static File testDir(final File dir, final boolean create, final boolean executable)
Returns the directory dir, which is processed and tested as described below.
Definition: IOUtil.java:1167
com.jogamp.common.util.IOUtil.filesOf
static ArrayList< String > filesOf(final List< String > paths, final List< Pattern > excludes, final List< Pattern > includes)
Retrieve the list of all filenames traversing through given paths.
Definition: IOUtil.java:1452
com.jogamp.common.util.IOUtil.getUriFilePathOrASCII
static String getUriFilePathOrASCII(final Uri uri)
If uri is a file scheme implementation returns Uri#toFile().
Definition: IOUtil.java:744
com.jogamp.common.util.IOUtil.copyURLConn2File
static int copyURLConn2File(final URLConnection conn, final File outFile)
Copy the complete specified URL resource to the specified output file.
Definition: IOUtil.java:182
com.jogamp.common.util.IOUtil.copyStream2ByteArray
static byte[] copyStream2ByteArray(InputStream stream)
Copy the complete specified input stream to a byte array, which is being returned.
Definition: IOUtil.java:262
com.jogamp.common.util.IOUtil.appendCharStream
static StringBuilder appendCharStream(final StringBuilder sb, final Reader r)
Definition: IOUtil.java:250
com.jogamp.common.util.IOUtil.copyStream2File
static int copyStream2File(final InputStream in, final File outFile)
Copy the complete specified input stream to the specified output file.
Definition: IOUtil.java:204
com.jogamp.common.util.IOUtil.close
static IOException close(final Closeable stream, final IOException[] saveOneIfFree, final PrintStream dumpExcess)
Helper to simplify closing Closeables.
Definition: IOUtil.java:1428
com.jogamp.common.util.InterruptSource.Thread
java.lang.Thread specialization implementing InterruptSource to track java.lang.Thread#interrupt() ca...
Definition: InterruptSource.java:80
com.jogamp.common.util.PropertyAccess
Helper routines for accessing properties.
Definition: PropertyAccess.java:36
com.jogamp.common.util.PropertyAccess.getBooleanProperty
static final boolean getBooleanProperty(final String property, final boolean jnlpAlias)
Definition: PropertyAccess.java:101
com.jogamp.common.util.PropertyAccess.isPropertyDefined
static final boolean isPropertyDefined(final String property, final boolean jnlpAlias)
Definition: PropertyAccess.java:115
com.jogamp.common.util.PropertyAccess.getProperty
static final String getProperty(final String propertyKey, final boolean jnlpAlias)
Query the property with the name propertyKey.
Definition: PropertyAccess.java:138
com.jogamp.common.util.ReflectionUtil
Definition: ReflectionUtil.java:56
com.jogamp.common.util.ReflectionUtil.getConstructor
static final Constructor<?> getConstructor(final String clazzName, final Class<?>[] cstrArgTypes, final boolean initializeClazz, final ClassLoader cl)
Definition: ReflectionUtil.java:183
com.jogamp.common.util.ReflectionUtil.getClass
static final Class<?> getClass(final String clazzName, final boolean initializeClazz, final ClassLoader cl)
Loads and returns the class or null.
Definition: ReflectionUtil.java:170
com.jogamp.common.util.SecurityUtil
Definition: SecurityUtil.java:39
com.jogamp.common.util.SecurityUtil.doPrivileged
static< T > T doPrivileged(final PrivilegedAction< T > o)
Call wrapper for java.security.AccessController#doPrivileged(PrivilegedAction).
Definition: SecurityUtil.java:78
com.jogamp.common.util.SecurityUtil.checkPermission
static final void checkPermission(final Permission perm)
Throws an SecurityException if an installed SecurityManager does not permit the requested Permission.
Definition: SecurityUtil.java:159
com.jogamp.common.os.Platform.CPUFamily
Definition: Platform.java:64
com.jogamp.common.os.Platform.CPUFamily.X86
X86
AMD/Intel.
Definition: Platform.java:66
com.jogamp.common.os.Platform.OSType
Definition: Platform.java:60
com.jogamp.common.os.Platform.OSType.IOS
IOS
Definition: Platform.java:61
com.jogamp.common.os.Platform.OSType.MACOS
MACOS
Definition: Platform.java:61
com.jogamp.common.util.InterruptSource
Interface exposing java.lang.Thread#interrupt() source, intended for java.lang.Thread specializations...
Definition: InterruptSource.java:36